def parser_html(self, response):
        path_one = '/data01/html/huanping/中华人民共和国生态环境部/{}/'\
            .format(time.strftime("%Y-%m-%d"))
        if not os.path.exists(path_one):
            os.makedirs(path_one)
        path = path_one + make_index(response.save['url'])
        with open(path, 'w+') as f:
            f.write(response.text)
        ob = BeautifulSoup(response.text, "html.parser")
        obTime = ob.find('span', class_="wzxq_fbt2").findAll("p")[0].getText()
        timeList = str(obTime).replace("\n", "").strip().split("-")
        table = ob.findAll("table")
        keys = []
        flag = 1
        objs = []
        '''judge include table '''
        if len(table) != 0:
            '''table is include a lagel'''
            if len(table[0].findAll("a")) != 0:
                rows = table[0].findAll("tr")
                for row in rows:
                    if flag == 1:
                        '''deal first row data'''
                        for cell in row.findAll(['td', 'th']):
                            keys.append(str(cell.get_text()).replace("\n", "").strip())
                        flag += 1
                    else:
                        if len(row.findAll("a")) != 0:
                            '''judge row is include  a label'''
                            obj = {}
                            data = {}
                            try:
                                for i in range(0, len(keys)):
                                    obj[keys[i]] = str(row.findAll(['td', 'th'])[i].get_text()).replace("\n",
                                                                                                        "")
                                    fileUrl = "http://hps.mee.gov.cn/jsxm/xmsl/" + timeList[0] + timeList[
                                        1] + "/" + row.findAll("a")[0].attrs['oldsrc']
                                obj["项目名称"] = str(obj["项目名称"]).replace("/", "每").strip()
                            except:
                                logging.error({"error": traceback.format_exc(), "filePath": path,
                                               "time": time.strftime("%Y-%m-%d %H:%M:%S")})
                            finally:
                                data["info"] = json.dumps(obj, ensure_ascii=False)
                                data["sub_url"] = ob.find(attrs={"name": "Url"})['content']
                                data["file_url"] = fileUrl
                                data["create_time"] = time.strftime("%Y-%m-%d %H:%M:%S")
                                data["source"] = "中华人民共和国生态环境部"
                                data["pdf_id"] = make_index(data["file_url"] + data["sub_url"])
                                data["file_name"] = obj["项目名称"]
                                data["path"] = "/data01/pdf/"
                                data["status"] = 0
                                data["topic"] = 'pdf_info'
                                objs.append(data)
                                sql = f"insert into {mysql_table_pdf_download}(info,sub_url,file_url," \
                                    f"file_name,path,source,status,pdf_id,create_time) values (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
                                mysql_tool(sql, [str(data["info"]), data["sub_url"], data["file_url"],
                                                 data["file_name"], data["path"], data["source"],
                                                 data["status"], data["pdf_id"],data["create_time"]])

        return objs
Beispiel #2
0
 def zjhp_parse_remains(self, response):
     data_list = []
     path_one = '/data01/html/huanping/浙江省生态环境厅/{}/'\
         .format(time.strftime("%Y-%m-%d"))
     if not os.path.exists(path_one):
         os.makedirs(path_one)
     path = path_one + make_index(response.save['url'])
     with open(path, 'w+') as f:
         f.write(response.text)
     oBject = BeautifulSoup(response.text, "html.parser")
     x = oBject.find("div", class_='mainContainer;').findAll('a')
     for i in range(len(x)):
         data_info = {}
         if 'Produced By 大汉网络 大汉版通发布系统' in x[i].getText():
             data_info['file_name'] = "UnknowPdfFile" + time.strftime(
                 "%Y-%m-%d %H:%M:%S")
         else:
             data_info['file_name'] = x[i].getText()[:-4]
         try:
             j = oBject.find(
                 "div", class_='mainContainer;').findAll('a')[i]['href']
             try:
                 url_part = re.findall(r"&filename=(.*?).pdf", j, re.S)[0]
                 if '/module/download/downfile.jsp?' in j:
                     data_info['file_url'] = (
                         'http://zjjcmspublic.oss-cn-hangzhou.aliyuncs.com/jcms_files'
                         '/jcms1/web1756/site/attach/-1/{}.pdf'.format(
                             url_part))
                 else:
                     data_info['file_url'] = url_part
             except IndexError:
                 url_part = 'http://zjjcmspublic.oss-cn-hangzhou.aliyuncs.com/jcms_files/jcms1/web1756/site{}'\
                     .format(j)
                 data_info['file_url'] = url_part
             finally:
                 data_info["info"] = "this html can not get html info"
                 data_info["sub_url"] = response.save['url']
                 data_info["create_time"] = time.strftime(
                     "%Y-%m-%d %H:%M:%S")
                 data_info["source"] = "浙江省环境生态厅"
                 data_info["pdf_id"] = make_index(data_info["file_url"] +
                                                  data_info["sub_url"])
                 data_info["path"] = "/data01/pdf/"
                 data_info["status"] = 0
                 data_info["topic"] = "pdf_info"
                 sql_query = f"insert into {mysql_table_pdf_download}(info,sub_url,file_url,file_name,path," \
                     f"source,status,pdf_id,create_time) values (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
                 mysql_tool(sql_query, [
                     str(data_info["info"]), data_info["sub_url"],
                     data_info["file_url"], data_info["file_name"],
                     data_info["path"], data_info["source"],
                     data_info["status"], data_info["pdf_id"],
                     data_info["create_time"]
                 ])
         except KeyError:
             logger.warning('this html has no pdf file')
         finally:
             data_list.append(data_info)
     return data_list
    def getItems(self, response):
        datas=[]
        if response.status_code == 200:
            ob = BeautifulSoup(response.text, "html.parser")
            '''get list'''
            items = ob.find('div', class_="main_rt_list").findAll("li")
            for item in items:
                html_info = {}

                '''get a label'''
                click = item.find("a")
                if click != None:
                    href = str(click.attrs['href'])[1:]
                    if href.endswith(".shtml"):
                        url = "http://hps.mee.gov.cn/jsxm/xmsl" + str(click.attrs['href'])[1:]
                        self.crawl(url, save={'url': url}, timeout=6, callback=self.parser_html)
                        html_info["url"] = url
                        html_info["create_time"] = time.strftime("%Y-%m-%d %H:%M:%S")
                        html_info["source"] = "中华人民共和国生态环境部"
                        html_info["status"] = 0
                        html_info["type"] = "huanping"
                        path = "/data01/html/" + html_info["type"] + "/" + html_info["source"] + \
                               "/" + html_info["create_time"][0:10] + "/"
                        id = make_index(html_info["url"] + path)
                        html_info["path"] = path
                        html_info["html_id"] = id
                        html_info['topic'] = "html_info"
                        sql = f"insert into {mysql_table_html_download}" \
                            f"(html_id,url,path,status,`type`,create_time) values (%s,%s,%s,%s,%s,%s)"
                        mysql_tool(sql, [str(html_info["html_id"]), html_info["url"], html_info["path"],
                                         html_info["status"], html_info["type"], html_info["create_time"]])
                    datas.append(html_info)
        return datas
Beispiel #4
0
 def zjhp_condition_remains(self, response):
     html_detail_tbody = BeautifulSoup(response.text, 'lxml')
     infos_list = []
     tbodys_one = html_detail_tbody.findAll("tr",
                                            class_='tr_main_value_even')
     tbodys_two = html_detail_tbody.findAll("tr",
                                            class_='tr_main_value_odd')
     for infos in tbodys_one + tbodys_two:
         html_info = {}
         if infos.a is not None:
             html_info["url"] = infos.a['href']
             self.crawl(infos.a['href'],
                        save={'url': infos.a['href']},
                        timeout=6,
                        callback=self.zjhp_parse_remains)
             html_info["create_time"] = time.strftime("%Y-%m-%d %H:%M:%S")
             html_info["source"] = "浙江省生态环境厅"
             html_info["type"] = "huanping"
             path = "/data01/html/" + html_info["type"] + "/" + html_info["source"] +\
                    "/" + html_info["create_time"][0:10] + "/"
             id = make_index(html_info["url"] + path)
             html_info["path"] = path
             html_info["html_id"] = id
             html_info["status"] = 0
             html_info['topic'] = "html_info"
             sql = f"insert into {mysql_table_html_download}" \
                 f"(html_id,url,path,status,`type`,create_time) values (%s,%s,%s,%s,%s,%s)"
             mysql_tool(sql, [
                 str(html_info["html_id"]), html_info["url"],
                 html_info["path"], html_info["status"], html_info["type"],
                 html_info["create_time"]
             ])
             infos_list.append(html_info)
     return infos_list
Beispiel #5
0
def arc_extraction(img,
                   orders,
                   extraction_width,
                   column_range,
                   gain=1,
                   readn=0,
                   dark=0,
                   plot=False,
                   **kwargs):
    logging.info("Using arc extraction to produce spectrum.")
    _, ncol = img.shape
    nord, _ = orders.shape

    if plot:
        # Prepare output image
        output = np.zeros((np.sum(extraction_width[1:-1]) + nord - 2, ncol))
        pos = [0]

    spectrum = np.zeros((nord - 2, ncol))
    uncertainties = np.zeros((nord - 2, ncol))
    x = np.arange(ncol)

    for i, onum in enumerate(range(1, nord - 1)):  # loop thru orders
        x_left_lim = column_range[onum, 0]  # First column to extract
        x_right_lim = column_range[onum, 1]  # Last column to extract

        ycen = np.polyval(orders[onum], x).astype(int)
        yb, yt = ycen - extraction_width[onum,
                                         0], ycen + extraction_width[onum, 1]
        index = make_index(yb, yt, x_left_lim, x_right_lim)

        # Sum over the prepared index
        arc = np.sum(img[index], axis=0)

        spectrum[i, x_left_lim:x_right_lim] = arc  # store total counts
        uncertainties[i, x_left_lim:x_right_lim] = (
            np.sqrt(np.abs(arc * gain + dark + readn**2)) / gain
        )  # estimate uncertainty

        if plot:
            output[pos[i]:pos[i] + index[0].shape[0],
                   x_left_lim:x_right_lim] = img[index]
            pos += [pos[i] + index[0].shape[0]]

    if plot:
        plt.imshow(output,
                   vmin=0,
                   vmax=np.mean(output) + 5 * np.std(output),
                   origin="lower")

        for i in range(nord - 2):
            tmp = spectrum[i] - np.min(
                spectrum[i, column_range[i + 1, 0]:column_range[i + 1, 1]])
            tmp = tmp / np.max(tmp) * 0.9 * (pos[i + 1] - pos[i])
            tmp += pos[i]
            tmp[tmp < pos[i]] = pos[i]
            plt.plot(x, tmp)

        plt.show()

    return spectrum, 0, uncertainties
Beispiel #6
0
def extract_spectrum(img,
                     ycen,
                     ylow,
                     yhigh,
                     xlow,
                     xhigh,
                     gain=1,
                     readn=0,
                     lambda_sf=0.1,
                     lambda_sp=0,
                     osample=1,
                     swath_width=None,
                     no_scatter=False,
                     telluric=False,
                     normalize=False,
                     scatter_below=0,
                     scatter_above=0,
                     yscatter_below=0,
                     yscatter_above=0,
                     threshold=0,
                     use_2d=False,
                     plot=False,
                     ord_num=0,
                     im_norm=None,
                     im_ordr=None,
                     **kwargs):

    if use_2d:
        raise NotImplementedError("Curved extraction not supported yet")

    nrow, ncol = img.shape
    noise = readn / gain
    irow = np.arange(nrow)
    ycene = ycen[xlow:xhigh]
    nysf = yhigh + ylow + 1
    yslitf = -ylow, yhigh

    spec = np.zeros(ncol)
    sunc = np.zeros(ncol)

    no_scatter = no_scatter or (np.all(scatter_below == 0)
                                and np.all(scatter_above == 0))

    if swath_width is None:
        i = np.unique(ycen.astype(int))  # Points of row crossing
        ni = len(
            i)  # This is how many times this order crosses to the next row
        if len(i) > 1:  # Curved order crosses rows
            i = np.sum(i[1:] - i[:-1]) / (len(i) - 1)
            nbin = np.clip(int(np.round(ncol / i)) // 3, 3,
                           20)  # number of swaths along the order
        else:  # Perfectly aligned orders
            nbin = np.clip(ncol // 400, 3,
                           None)  # Still follow the changes in PSF
        nbin = nbin * (xhigh -
                       xlow) // ncol  # Adjust for the true order length
    else:
        nbin = np.clip(int(np.round((xhigh - xlow) / swath_width)), 1, None)

    nslitf = osample * (ylow + yhigh + 2) + 1
    slitf = np.zeros((2 * nbin, nslitf))

    # Define order boundary
    yc = ycen.astype(int)
    ymin = ycen - ylow
    ymax = ycen + yhigh

    # Calculate boundaries of distinct slitf regions
    # Here is the layout to understand the lines below
    #
    #        1st swath    3rd swath    5th swath      ...
    #     /============|============|============|============|============|
    #
    #               2nd swath    4th swath    6th swath
    #            |------------|------------|------------|------------|
    #            |.....|
    #            overlap
    #
    #            +     ******* 1
    #             +   *
    #              + *
    #               *            weights (+) previous swath, (*) current swath
    #              * +
    #             *   +
    #            *     +++++++ 0

    bins = np.linspace(xlow, xhigh, 2 * nbin + 1)  # boundaries of bins
    ibeg_half = np.ceil(bins[:-2]).astype(int)  # beginning of each bin
    iend_half = np.floor(bins[2:]).astype(int)  # end of each bin

    # Perform slit decomposition within each swath stepping through the order with
    # half swath width. Spectra for each decomposition are combined with linear weights.
    for ihalf in range(0, 2 * nbin - 1):  # loop through swaths
        ib = ibeg_half[ihalf]  # left column
        ie = iend_half[ihalf] + 1  # right column
        nc = ie - ib  # number of columns in swath
        logging.debug("Extractiing Swath %i, Columns: %i - %i", ihalf, ib, ie)

        # Weight for combining overlapping regions
        weight = np.ones(nc)
        if ihalf > 0:
            weight[:nc // 2 + 1] = np.arange(nc // 2 + 1) / nc * 2
        oweight = 1 - weight

        # Cut out swath from image
        index = make_index(yc - ylow, yc + yhigh, ib, ie)
        sf = img[index]

        # Telluric
        if telluric:
            tel_lim = (telluric if telluric > 5 and telluric < nysf / 2 else
                       min(5, nysf / 3))
            tel = np.sum(sf, axis=0)
            itel = np.arange(nysf)
            itel = itel[np.abs(itel - nysf / 2) >= tel_lim]
            tel = sf[itel, :]
            sc = np.zeros(nc)

            for itel in range(nc):
                sc[itel] = np.median(tel[itel])

            tell = sc
        else:
            tell = 0

        if not no_scatter:
            # y indices
            index_y = np.array(
                [np.arange(k, nysf + k) for k in yc[ib:ie] - yslitf[0]])
            dy_scatter = (index_y.T - yscatter_below[None, ib:ie]) / (
                yscatter_above[None, ib:ie] - yscatter_below[None, ib:ie])
            scatter = (scatter_above[None, ib:ie] - scatter_below[None, ib:ie]
                       ) * dy_scatter + scatter_below[None, ib:ie]
        else:
            scatter = 0

        # Do Slitfunction extraction
        sf -= scatter + tell
        sf = np.clip(sf, 0, None)

        # offset from the central line
        y_offset = ycen[ib:ie] - yc[ib:ie]
        # if use_2d:
        #     sp, sfsm, model, unc = slitfunc_curved(
        #         sf,
        #         y_offset,
        #         tilt,
        #         lambda_sp=lambda_sp,
        #         lambda_sl=lambda_sf,
        #         osample=osample,
        #     )
        #     delta_x = None  # TODO get this from slitfunc_curved
        # else:
        sp, sfsm, model, unc = slitfunc(sf,
                                        y_offset,
                                        lambda_sp=lambda_sp,
                                        lambda_sf=lambda_sf,
                                        osample=osample)

        if normalize:
            # In case we do FF normalization replace the original image by the
            # ratio of sf/sfbin where number of counts is larger than threshold
            # and with 1 elsewhere
            scale = 1

            ii = np.where(model > threshold / gain)
            sss = np.ones((nysf, nc))
            ddd = np.copy(model)
            sss[ii] = sf[ii] / model[ii]

            if ihalf > 0:
                overlap = iend_half[ihalf - 1] - ibeg_half[ihalf] + 1
                sss[ii] /= scale
                sp *= scale
            else:
                nc_old = nc
                sss_old = np.zeros((nysf, nc))
                ddd_old = np.zeros((nysf, nc))
                overlap = ibeg_half[1] - ibeg_half[0]

            # Combine new and old sections
            ncc = overlap

            index = make_index(yc + yslitf[0], yc + yslitf[1], ib, ib + ncc)
            im_norm[index] = (sss_old[:, -ncc:] * oweight[:ncc] +
                              sss[:, :ncc] * weight[:ncc])
            im_ordr[index] = (ddd_old[:, -ncc:] * oweight[:ncc] +
                              ddd[:, :ncc] * weight[:ncc])

            if ihalf == 2 * nbin - 2:
                # TODO check
                index = make_index(yc + yslitf[0], yc + yslitf[1], ib + ncc,
                                   ib + nc)
                im_norm[index] = sss[:, ncc:nc]
                im_ordr[index] = ddd[:, ncc:nc]

            nc_old = nc
            sss_old = np.copy(sss)
            ddd_old = np.copy(ddd)

        # Combine overlaping regions
        # TODO
        # if use_2d:
        #     if ihalf > 0 and ihalf < 2 * nbin - 2:
        #         spec[ib + delta_x : ie - delta_x] = (
        #             spec[ib + delta_x : ie - delta_x] * oweight[delta_x : nc - delta_x]
        #             + sp[delta_x:-delta_x] * weight[delta_x:-delta_x]
        #         )
        #     elif ihalf == 0:
        #         spec[ib : ie - delta_x] = sp[:-delta_x]
        #     elif ihalf == 2 * nbin - 2:
        #         spec[ib + delta_x : ie] = (
        #             spec[ib + delta_x : ie] * oweight[delta_x:-1]
        #             + sp[delta_x:-1] * weight[delta_x:-1]
        #         )
        # else:

        spec[ib:ie] = spec[ib:ie] * oweight + sp * weight
        sunc[ib:ie] = sunc[ib:ie] * oweight + unc * weight

        if plot:
            plot_slitfunction(sf, sp, sfsm, model, y_offset, ord_num, ib, ie,
                              osample)

    # TODO ????? is that really correct
    sunc = np.sqrt(sunc + spec)

    # TODO what to return ?
    slitf = np.mean(slitf, axis=0)
    model = spec[:, None] * slitf[None, :]
    return spec, slitf, model, sunc
Beispiel #7
0
def make_scatter(im, orders, **kwargs):
    """
    This subroutine is still far from perfect. NP wrote it in 2002 and since it
    was a pain in the back. The problem is that that it works very smoothlu with
    a good data set but once we get to the low S/N, overlapping orders and bad
    cosmetics things starting to fail. Typical failures are connected to the
    the identification of the walls of adjucent orders and the bottom.
    
    History of modifications:
    2006-09-26 (NP) the condition for local maxima ID is set to
    (positive left der and non-positive right der) or
    (non-negative left der and negative right der)
    """

    # Get image size.
    nrow, ncol = im.shape
    first = 0  # first order
    last = len(orders) + 1  # last order
    nord = len(orders)

    # Get kwargs data, TODO change names
    ccd_gain = kwargs.get("gain", 1)
    ccd_rdnoise = kwargs.get("readn", 0) / ccd_gain
    osamp = kwargs.get("osample", 10)
    lambda_sf = kwargs.get("lambda_sf", 1)
    lambda_sp = kwargs.get("lambda_sp", 0)
    extra_offset = kwargs.get("order_extra_width", 1)
    width = kwargs.get("swath_width", 400)
    column_range = kwargs.get("column_range", np.tile([0, ncol], (nord, 0)))

    debug = kwargs.get("debug", False)
    pol = kwargs.get("pol", False)
    subtract = kwargs.get("subtract", False)

    # Initialize arrays.
    xcol = np.arange(ncol)  # indices of all columns
    back = np.zeros((nord + 1, ncol))  # fitted scattered light model
    back_data = np.zeros((nord + 1, ncol))  # scattered light data
    yback = np.zeros((nord + 1, ncol))  # scattered light coordinates
    ycen1 = np.polyval(orders[0], xcol)  # the shape of the starting order

    # TODO DEBUG
    # plt.ion()

    # Loop over neighbouring orders, (0, 1), (1, 2), (2, 3), ...
    for order0, order1 in zip(range(first, last), range(first + 1, last + 1)):
        logging.debug("orders: %i, %i" % (order0, order1))
        # Calculate shapes
        ycen0 = np.polyval(orders[order0], xcol)
        ycen1 = np.polyval(orders[order1], xcol)

        cr0 = column_range[order0]
        cr1 = column_range[order1]

        ibeg = max(cr0[0], cr1[0])  # left boundary to consider
        iend = min(cr0[1], cr1[1])  # right boundary to consider
        width = np.clip(
            (iend - ibeg) * 0.1, width,
            None)  # width to consider (swath < width < iend-ibeg+1)

        width = int(width // 2)  # half-width to avoid rounding errors
        height = np.mean(ycen1[ibeg:iend] - ycen0[ibeg:iend])  # mean height
        height = int(np.round(height * 0.5 * extra_offset))
        height = np.clip(height, 3,
                         None)  # half-height to avoid rounding errors

        icen = (ibeg + iend) // 2  # central column
        ibeg = np.clip(icen - width, ibeg,
                       None)  # starting column of the region of interest
        iend = np.clip(icen + width, None,
                       iend)  # ending column of the region of interest
        ycen = 0.5 * (ycen1 + ycen0)  # central line of the troff
        ymin = ycen.astype(
            int) - height  # bottom boundary of the region of interest
        ymax = ycen.astype(
            int) + height  # top boundary of the region of interest

        yback[order1, :] = ycen  # scattered light coordinates

        # Copy the region of interest to sf, j=0..nc
        index = make_index(ymin, ymax, ibeg, iend)
        sf = im[index]

        sf = sf - np.min(sf)
        tmp = ycen[ibeg:iend] - ycen[ibeg:iend].astype(int)

        # TODO debug
        # plt.imshow(sf)
        # plt.plot(sf.shape[0]/2 + tmp)
        # plt.show()

        # TODO why is this so slow?
        # TODO use passed parameters
        osamp = 1
        # TODO: Copying these ensures that nothing bad happens during slitfunc, which sometimes happens otherwise
        sf = np.copy(sf)
        tmp = np.copy(tmp)
        sp, sfsm, model, unc = slitfunc(sf,
                                        tmp,
                                        lambda_sp=2,
                                        lambda_sf=2,
                                        osample=1)
        nslitf = len(sfsm)
        yslitf = (np.arange(-0.5, nslitf - 0.5, 1) / osamp - 1.5 - height
                  )  # final subpixel scale

        dev = (ccd_rdnoise / ccd_gain / np.sqrt(np.sum(sp))
               )  # typical pixel scatter normalized to counts

        var = np.std(sfsm)

        #
        # This is an improved version which is near the final form
        #
        jback = bottom(np.clip(sfsm, None, np.median(sfsm)),
                       1,
                       eps=dev,
                       poly=True)  # fit the bottom with a smooth curve
        jback = np.clip(sfsm - jback, 0, None)  # find all positive spikes

        # ===========================================================================
        k = np.where(sfsm > np.median(sfsm) + 0.5 * var)[0]
        nback = k.shape[0]
        if nback > 0:
            m1 = np.where(yslitf[k] <
                          0)  # part of the gap which is below the central line
            m2 = np.where(yslitf[k] >
                          0)  # part of the gap which is above the central line
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        else:
            n1 = 0
            n2 = 0
        if n1 == 0 or n2 == 0:  # this happens e.g. if the two adjacent
            # orders have dramatically different level
            # of signal
            k = np.where(sfsm > middle(sfsm, 1, eps=dev, poly=True))[0]
            m1 = np.where(yslitf[k] < 0)
            m2 = np.where(yslitf[k] > 0)
            nback = k.shape[0]
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        if n1 == 0 or n2 == 0:  # this happens e.g. if the two adjacent
            # orders have dramatically different level
            # of signal
            k = np.where(sfsm > middle(sfsm, 1e3, eps=dev))[0]
            m1 = np.where(yslitf[k] < 0)
            m2 = np.where(yslitf[k] > 0)
            nback = k.shape[0]
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        ss = np.array([0, *jback, 0])
        kk = np.where(((ss[k + 1] >= ss[k]) & (ss[k + 1] > ss[k + 2]))
                      | ((ss[k + 1] > ss[k]) & (ss[k + 1] >= ss[k + 2])))
        k = k[kk]

        m1 = np.where(
            yslitf[k] < 0)  # part of the gap which is below the central line
        m2 = np.where(
            yslitf[k] > 0)  # part of the gap which is above the central line
        n1 = m1[0].shape[0]
        n2 = m2[0].shape[0]
        # ===========================================================================

        if n1 == 0 or n2 == 0:  # ultimate method
            logging.info(
                "mkscatter: failed finding interorder boundaries. Using 5 pixels around central line."
            )
            k = np.sort(abs(yslitf))[0] + [-3, 3]
            nback = len(k)
            debug = True

        if nback < 2 or (nback >= 2 and
                         (np.min(yslitf[k]) > height * 0.5
                          or np.max(yslitf[k]) < -height * 0.5)):
            n1 = np.min(np.abs(yslitf +
                               height * 0.5))  # in this case just select
            n2 = np.min(np.abs(yslitf - height * 0.5))  # the central half
            k1 = n1.shape[0]
            k2 = n2.shape[0]
            k = [k1, k2]
            nback = 2

        if jback[0] >= jback[1]:
            k = np.array([0, *k])
            nback = nback + 1
        if jback[nslitf - 1] >= jback[nslitf - 2]:
            k = np.array([*k, nslitf - 1])
            nback = nback + 1

        if debug:
            plt.plot(yslitf, sfsm)
            plt.plot(yslitf, middle(sfsm, 1, eps=dev, poly=True))
            plt.plot(yslitf, middle(sfsm, 1e3, eps=dev, poly=True))
            plt.hline(np.median(sfsm) + 0.5 * var)
            plt.plot(yslitf[k], sfsm[k])
            plt.show()

        jback = np.where(yslitf[k] < 0)[0]
        n1 = jback.shape[0]
        imax1 = np.argmax(yslitf[k[jback]])
        m1 = yslitf[k[jback]][imax1]
        imax1 = k[jback[imax1]]

        jback = np.where(yslitf[k] > 0)[0]
        n2 = jback.shape[0]
        imax2 = np.argmin(yslitf[k[jback]])
        m2 = yslitf[k[jback]][imax2]
        imax2 = k[jback[imax2]]

        k = [imax1, imax2]
        if nback == 0:
            print(
                "mkscatter: failed to find the boundaries of the inter-order troff using default orders: %i-%i x-range: (%i,%i)"
                % (order0, order1, ibeg, iend))
            k = [0, len(nslitf)]

        tmp = np.clip(sfsm[k[0]:k[1]], None, np.median(sfsm))
        jback = bottom(sfsm[k[0]:k[1]], 1, eps=dev,
                       poly=True)  # fit bottom with a straight line
        iback = np.where(sfsm[k[0]:k[1]] <= jback +
                         ccd_rdnoise)[0]  # find all the points below
        nback = iback.shape[0]
        if nback <= 5:
            plt.plot(yslitf, sfsm)
            plt.plot(
                yslitf,
                bottom(np.clip(sfsm, None, np.median(sfsm)),
                       1,
                       eps=dev,
                       poly=True),
            )
            plt.plot(yslitf[k], sfsm[k], "*")
            raise Exception(
                "mkscatter: major error in the order format: could not detect inter-order troff"
            )
        iback += k[0]
        imax1 = np.min(iback)
        imax2 = np.max(iback)
        sf1 = sfsm[iback]

        step = (max(sf1) - min(sf1)) / np.clip(len(sf1) / 10, 10, 200)
        nh = int(1 / step)
        h, _ = np.histogram(sf1, bins=nh)
        ihmax = np.argmax(h)
        hmax = h[ihmax]

        i0 = np.where(h[:ihmax] < 0.1 * hmax)
        n1 = i0[0].shape[0]
        i0 = np.max(i0) if n1 > 0 else 0

        i1 = np.where(h[ihmax:] < 0.1 * hmax)[0]
        n2 = i1.shape[0]
        i1 = np.min(i1) + ihmax if n2 > 0 else nh - 1

        ii = (np.where((sf1 - min(sf1) >= step * i0)
                       & (sf1 - min(sf1) < step * i1))[0] + imax1)
        nii1 = ii.shape[0]
        if nii1 <= 0:
            raise Exception(
                "mkscatter: could not detect background points between orders %i and %i"
                % (order0, order1))

        y1 = np.ceil(np.min(yslitf[ii]))  # bottom boundary of the troff
        y2 = np.floor(np.max(yslitf[ii]))  # top boundary of the troff

        for j in range(ncol):  # scattered light in col j
            back_data[order1,
                      j] = interpolate_bad_pixels(ycen[j], y1, y2, im, j, nrow)

            if order0 == first:  # for the first order try
                yy = ycen0[j] - (ycen[j] - ycen0[j]
                                 )  # to find background below
                yback[0, j] = yy  # scattered light coordinates
                back_data[0,
                          j] = interpolate_bad_pixels(yy, y1, y2, im, j, nrow)
            elif order1 == last:  # for the last order try
                yy = ycen1[j] + (ycen1[j] - ycen[j]
                                 )  # to find background above
                yback[-1, j] = yy  # scattered light coordinates
                back_data[-1,
                          j] = interpolate_bad_pixels(yy, y1, y2, im, j, nrow)

        if (order1 % 10) == 5 or (order1 % 10) == 0 or nord < 10:
            logging.info("mkscatter: order %i of total  %i was processed",
                         order1, last)

    # bad pixels are masked out
    back_data = np.ma.masked_array(back_data, mask=back_data == -1000)

    # Interpolate missing data from the adjacent troffs
    for i in range(ncol):
        back_data[:, i] = np.interp(yback[:, i], yback[:, i], back_data[:, i])

    # Filter out noise: 0th background troff
    crange = column_range[0]
    x = np.arange(crange[0], crange[1])
    b = middle(back_data[0, x], 20., eps=dev)
    if pol:
        back[0, x] = middle(b, 11, poly=True, eps=dev, min=0)
    else:
        back[0, x] = middle(b, lambda_sp, eps=dev, min=0)

    # All intermediate background troffs
    if nord > 1:
        for order0, order1 in zip(range(first, last),
                                  range(first + 1, last + 1)):
            cr0 = column_range[order0]
            cr1 = column_range[order1]

            crange = (
                max(cr0[0], cr1[0]),
                min(cr0[1], cr1[1]),
            )  # right boundary to consider

            x = np.arange(crange[0], crange[1])
            b = middle(back_data[order1, x], 20., eps=dev)
            if pol:
                back[order1, x] = middle(b,
                                         11,
                                         poly=True,
                                         eps=dev,
                                         min=0,
                                         double=True)
            else:
                back[order1, x] = middle(b, lambda_sp, eps=dev, min=0)

    # The last background troff
    crange = column_range[last]
    x = np.arange(crange[0], crange[1])
    b = middle(back_data[last, x], 20., eps=dev)
    if pol:
        back[-1, x] = bottom(b, 11, poly=True, eps=dev, min=0)
    else:
        back[-1, x] = bottom(b, lambda_sp, eps=dev, min=0)

    if subtract:
        # Type conversion to avoid problems with UINT arrays when subtracting

        im = im.astype(np.float32)
        ycen = np.arange(nrow)
        if pol:
            ii = np.arange(0, nord, 2)  # polarization: orders come in pairs
            ii = np.array([*ii, np.max(ii) + 2
                           ])  # do not use interpolarization space
        else:
            ii = np.arange(nord)  # no polarization, count all orders

        for j in range(ncol):
            b = back[:, j]
            b = b[ii]
            y = yback[:, j]
            y = y[ii]
            im[:, j] -= np.interp(ycen, y, b)

    return back, yback
Beispiel #8
0
def make_scatter(im, orders, **kwargs):
    """
    This subroutine is still far from perfect. NP wrote it in 2002 and since it
    was a pain in the back. The problem is that that it works very smoothlu with
    a good data set but once we get to the low S/N, overlapping orders and bad
    cosmetics things starting to fail. Typical failures are connected to the
    the identification of the walls of adjucent orders and the bottom.
    
    History of modifications:
    2006-09-26 (NP) the condition for local maxima ID is set to
    (positive left der and non-positive right der) or
    (non-negative left der and negative right der)
    """

    # Get image size.
    nrow, ncol = im.shape
    first = 0  # first order
    last = len(orders) + 1  # last order
    nord = len(orders)

    # Get kwargs data, TODO change names
    ccd_gain = kwargs.get("gain", 1)
    ccd_rdnoise = kwargs.get("readn", 0) / ccd_gain
    osamp = kwargs.get("osample", 10)
    lambda_sf = kwargs.get("lambda_sf", 1)
    lambda_sp = kwargs.get("lambda_sp", 0)
    extra_offset = kwargs.get("order_extra_width", 1)
    width = kwargs.get("swath_width", 400)
    column_range = kwargs.get("column_range", np.tile([0, ncol], (nord, 0)))

    debug = kwargs.get("debug", False)
    pol = kwargs.get("pol", False)
    subtract = kwargs.get("subtract", False)

    # Initialize arrays.
    xcol = np.arange(ncol)  # indices of all columns
    back = np.zeros((nord + 1, ncol))  # fitted scattered light model
    back_data = np.zeros((nord + 1, ncol))  # scattered light data
    yback = np.zeros((nord + 1, ncol))  # scattered light coordinates
    ycen1 = np.polyval(orders[0], xcol)  # the shape of the starting order

    # TODO DEBUG
    # plt.ion()

    # Loop over neighbouring orders, (0, 1), (1, 2), (2, 3), ...
    for order0, order1 in zip(range(first, last), range(first + 1, last + 1)):
        logging.debug("orders: %i, %i" % (order0, order1))
        # Calculate shapes
        ycen0 = np.polyval(orders[order0], xcol)
        ycen1 = np.polyval(orders[order1], xcol)

        cr0 = column_range[order0]
        cr1 = column_range[order1]

        ibeg = max(cr0[0], cr1[0])  # left boundary to consider
        iend = min(cr0[1], cr1[1])  # right boundary to consider
        width = np.clip(
            (iend - ibeg) * 0.1, width, None
        )  # width to consider (swath < width < iend-ibeg+1)

        width = int(width // 2)  # half-width to avoid rounding errors
        height = np.mean(ycen1[ibeg:iend] - ycen0[ibeg:iend])  # mean height
        height = int(np.round(height * 0.5 * extra_offset))
        height = np.clip(height, 3, None)  # half-height to avoid rounding errors

        icen = (ibeg + iend) // 2  # central column
        ibeg = np.clip(
            icen - width, ibeg, None
        )  # starting column of the region of interest
        iend = np.clip(
            icen + width, None, iend
        )  # ending column of the region of interest
        ycen = 0.5 * (ycen1 + ycen0)  # central line of the troff
        ymin = ycen.astype(int) - height  # bottom boundary of the region of interest
        ymax = ycen.astype(int) + height  # top boundary of the region of interest

        yback[order1, :] = ycen  # scattered light coordinates

        # Copy the region of interest to sf, j=0..nc
        index = make_index(ymin, ymax, ibeg, iend)
        sf = im[index]

        sf = sf - np.min(sf)
        tmp = ycen[ibeg:iend] - ycen[ibeg:iend].astype(int)

        # TODO debug
        # plt.imshow(sf)
        # plt.plot(sf.shape[0]/2 + tmp)
        # plt.show()

        # TODO why is this so slow?
        # TODO use passed parameters
        osamp = 1
        # TODO: Copying these ensures that nothing bad happens during slitfunc, which sometimes happens otherwise
        sf = np.copy(sf)
        tmp = np.copy(tmp)
        sp, sfsm, model, unc = slitfunc(sf, tmp, lambda_sp=2, lambda_sf=2, osample=1)
        nslitf = len(sfsm)
        yslitf = (
            np.arange(-0.5, nslitf - 0.5, 1) / osamp - 1.5 - height
        )  # final subpixel scale

        dev = (
            ccd_rdnoise / ccd_gain / np.sqrt(np.sum(sp))
        )  # typical pixel scatter normalized to counts

        var = np.std(sfsm)

        #
        # This is an improved version which is near the final form
        #
        jback = bottom(
            np.clip(sfsm, None, np.median(sfsm)), 1, eps=dev, poly=True
        )  # fit the bottom with a smooth curve
        jback = np.clip(sfsm - jback, 0, None)  # find all positive spikes

        # ===========================================================================
        k = np.where(sfsm > np.median(sfsm) + 0.5 * var)[0]
        nback = k.shape[0]
        if nback > 0:
            m1 = np.where(
                yslitf[k] < 0
            )  # part of the gap which is below the central line
            m2 = np.where(
                yslitf[k] > 0
            )  # part of the gap which is above the central line
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        else:
            n1 = 0
            n2 = 0
        if n1 == 0 or n2 == 0:  # this happens e.g. if the two adjacent
            # orders have dramatically different level
            # of signal
            k = np.where(sfsm > middle(sfsm, 1, eps=dev, poly=True))[0]
            m1 = np.where(yslitf[k] < 0)
            m2 = np.where(yslitf[k] > 0)
            nback = k.shape[0]
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        if n1 == 0 or n2 == 0:  # this happens e.g. if the two adjacent
            # orders have dramatically different level
            # of signal
            k = np.where(sfsm > middle(sfsm, 1e3, eps=dev))[0]
            m1 = np.where(yslitf[k] < 0)
            m2 = np.where(yslitf[k] > 0)
            nback = k.shape[0]
            n1 = m1[0].shape[0]
            n2 = m2[0].shape[0]
        ss = np.array([0, *jback, 0])
        kk = np.where(
            ((ss[k + 1] >= ss[k]) & (ss[k + 1] > ss[k + 2]))
            | ((ss[k + 1] > ss[k]) & (ss[k + 1] >= ss[k + 2]))
        )
        k = k[kk]

        m1 = np.where(yslitf[k] < 0)  # part of the gap which is below the central line
        m2 = np.where(yslitf[k] > 0)  # part of the gap which is above the central line
        n1 = m1[0].shape[0]
        n2 = m2[0].shape[0]
        # ===========================================================================

        if n1 == 0 or n2 == 0:  # ultimate method
            logging.info(
                "mkscatter: failed finding interorder boundaries. Using 5 pixels around central line."
            )
            k = np.sort(abs(yslitf))[0] + [-3, 3]
            nback = len(k)
            debug = True

        if nback < 2 or (
            nback >= 2
            and (np.min(yslitf[k]) > height * 0.5 or np.max(yslitf[k]) < -height * 0.5)
        ):
            n1 = np.min(np.abs(yslitf + height * 0.5))  # in this case just select
            n2 = np.min(np.abs(yslitf - height * 0.5))  # the central half
            k1 = n1.shape[0]
            k2 = n2.shape[0]
            k = [k1, k2]
            nback = 2

        if jback[0] >= jback[1]:
            k = np.array([0, *k])
            nback = nback + 1
        if jback[nslitf - 1] >= jback[nslitf - 2]:
            k = np.array([*k, nslitf - 1])
            nback = nback + 1

        if debug:
            plt.plot(yslitf, sfsm)
            plt.plot(yslitf, middle(sfsm, 1, eps=dev, poly=True))
            plt.plot(yslitf, middle(sfsm, 1e3, eps=dev, poly=True))
            plt.hline(np.median(sfsm) + 0.5 * var)
            plt.plot(yslitf[k], sfsm[k])
            plt.show()

        jback = np.where(yslitf[k] < 0)[0]
        n1 = jback.shape[0]
        imax1 = np.argmax(yslitf[k[jback]])
        m1 = yslitf[k[jback]][imax1]
        imax1 = k[jback[imax1]]

        jback = np.where(yslitf[k] > 0)[0]
        n2 = jback.shape[0]
        imax2 = np.argmin(yslitf[k[jback]])
        m2 = yslitf[k[jback]][imax2]
        imax2 = k[jback[imax2]]

        k = [imax1, imax2]
        if nback == 0:
            print(
                "mkscatter: failed to find the boundaries of the inter-order troff using default orders: %i-%i x-range: (%i,%i)"
                % (order0, order1, ibeg, iend)
            )
            k = [0, len(nslitf)]

        tmp = np.clip(sfsm[k[0] : k[1]], None, np.median(sfsm))
        jback = bottom(
            sfsm[k[0] : k[1]], 1, eps=dev, poly=True
        )  # fit bottom with a straight line
        iback = np.where(sfsm[k[0] : k[1]] <= jback + ccd_rdnoise)[
            0
        ]  # find all the points below
        nback = iback.shape[0]
        if nback <= 5:
            plt.plot(yslitf, sfsm, xs=1)
            plt.plot(
                yslitf,
                bottom(np.clip(sfsm, None, np.median(sfsm)), 1, eps=dev, poly=True),
            )
            plt.plot(yslitf[k], sfsm[k], psym=2)
            raise Exception(
                "mkscatter: major error in the order format: could not detect inter-order troff"
            )
        iback += k[0]
        imax1 = np.min(iback)
        imax2 = np.max(iback)
        sf1 = sfsm[iback]

        step = (max(sf1) - min(sf1)) / np.clip(len(sf1) / 10, 10, 200)
        nh = int(1 / step)
        h, _ = np.histogram(sf1, bins=nh)
        ihmax = np.argmax(h)
        hmax = h[ihmax]

        i0 = np.where(h[:ihmax] < 0.1 * hmax)
        n1 = i0[0].shape[0]
        i0 = np.max(i0) if n1 > 0 else 0

        i1 = np.where(h[ihmax:] < 0.1 * hmax)[0]
        n2 = i1.shape[0]
        i1 = np.min(i1) + ihmax if n2 > 0 else nh - 1

        ii = (
            np.where((sf1 - min(sf1) >= step * i0) & (sf1 - min(sf1) < step * i1))[0]
            + imax1
        )
        nii1 = ii.shape[0]
        if nii1 <= 0:
            raise Exception(
                "mkscatter: could not detect background points between orders %i and %i"
                % (order0, order1)
            )

        y1 = np.ceil(np.min(yslitf[ii]))  # bottom boundary of the troff
        y2 = np.floor(np.max(yslitf[ii]))  # top boundary of the troff

        for j in range(ncol):  # scattered light in col j
            back_data[order1, j] = interpolate_bad_pixels(ycen[j], y1, y2, im, j, nrow)

            if order0 == first:  # for the first order try
                yy = ycen0[j] - (ycen[j] - ycen0[j])  # to find background below
                yback[0, j] = yy  # scattered light coordinates
                back_data[0, j] = interpolate_bad_pixels(yy, y1, y2, im, j, nrow)
            elif order1 == last:  # for the last order try
                yy = ycen1[j] + (ycen1[j] - ycen[j])  # to find background above
                yback[-1, j] = yy  # scattered light coordinates
                back_data[-1, j] = interpolate_bad_pixels(yy, y1, y2, im, j, nrow)

        if (order1 % 10) == 5 or (order1 % 10) == 0 or nord < 10:
            logging.info("mkscatter: order %i of total  %i was processed", order1, last)

    # bad pixels are masked out
    back_data = np.ma.masked_array(back_data, mask=back_data == -1000)

    # Interpolate missing data from the adjacent troffs
    for i in range(ncol):
        back_data[:, i] = np.interp(yback[:, i], yback[:, i], back_data[:, i])

    # Filter out noise: 0th background troff
    crange = column_range[0]
    x = np.arange(crange[0], crange[1])
    b = middle(back_data[0, x], 20., eps=dev)
    if pol:
        back[0, x] = middle(b, 11, poly=True, eps=dev, min=0)
    else:
        back[0, x] = middle(b, lambda_sp, eps=dev, min=0)

    # All intermediate background troffs
    if nord > 1:
        for order0, order1 in zip(range(first, last), range(first + 1, last + 1)):
            cr0 = column_range[order0]
            cr1 = column_range[order1]

            crange = (
                max(cr0[0], cr1[0]),
                min(cr0[1], cr1[1]),
            )  # right boundary to consider

            x = np.arange(crange[0], crange[1])
            b = middle(back_data[order1, x], 20., eps=dev)
            if pol:
                back[order1, x] = middle(b, 11, poly=True, eps=dev, min=0, double=True)
            else:
                back[order1, x] = middle(b, lambda_sp, eps=dev, min=0)

    # The last background troff
    crange = column_range[last]
    x = np.arange(crange[0], crange[1])
    b = middle(back_data[last, x], 20., eps=dev)
    if pol:
        back[-1, x] = bottom(b, 11, poly=True, eps=dev, min=0)
    else:
        back[-1, x] = bottom(b, lambda_sp, eps=dev, min=0)

    if subtract:
        # Type conversion to avoid problems with UINT arrays when subtracting

        im = im.astype(np.float32)
        ycen = np.arange(nrow)
        if pol:
            ii = np.arange(0, nord, 2)  # polarization: orders come in pairs
            ii = np.array([*ii, np.max(ii) + 2])  # do not use interpolarization space
        else:
            ii = np.arange(nord)  # no polarization, count all orders

        for j in range(ncol):
            b = back[:, j]
            b = b[ii]
            y = yback[:, j]
            y = y[ii]
            im[:, j] -= np.interp(ycen, y, b)

    return back, yback
Beispiel #9
0
def make_slitfunction(
    img,
    ycen,
    ylow,
    yhigh,
    xlow,
    xhigh,
    gain=1,
    readn=0,
    lambda_sf=0.1,
    lambda_sp=0,
    osample=1,
    swath_width=None,
    no_scatter=False,
    telluric=False,
    normalize=False,
    scatter_below=0,
    scatter_above=0,
    yscatter_below=0,
    yscatter_above=0,
    threshold=0,
    use_2d=False,
    plot=False,
    ord_num=0,
    im_norm=None,
    im_ordr=None,
    **kwargs
):

    nrow, ncol = img.shape
    noise = readn / gain
    irow = np.arange(nrow)
    ycene = ycen[xlow:xhigh]
    nysf = yhigh + ylow + 1
    yslitf = -ylow, yhigh

    spec = np.zeros(ncol)
    sunc = np.zeros(ncol)

    no_scatter = no_scatter or (
        np.all(scatter_below == 0) and np.all(scatter_above == 0)
    )

    if swath_width is None:
        i = np.unique(ycen.astype(int))  # Points of row crossing
        ni = len(i)  # This is how many times this order crosses to the next row
        if len(i) > 1:  # Curved order crosses rows
            i = np.sum(i[1:] - i[:-1]) / (len(i) - 1)
            nbin = np.clip(
                int(np.round(ncol / i)) // 3, 3, 20
            )  # number of swaths along the order
        else:  # Perfectly aligned orders
            nbin = np.clip(ncol // 400, 3, None)  # Still follow the changes in PSF
        nbin = nbin * (xhigh - xlow) // ncol  # Adjust for the true order length
    else:
        nbin = np.clip(int(np.round((xhigh - xlow) / swath_width)), 1, None)

    nslitf = osample * (ylow + yhigh + 2) + 1
    slitf = np.zeros((2 * nbin, nslitf))

    # Define order boundary
    yc = ycen.astype(int)
    ymin = ycen - ylow
    ymax = ycen + yhigh

    # Calculate boundaries of distinct slitf regions
    # Here is the layout to understand the lines below
    #
    #        1st swath    3rd swath    5th swath      ...
    #     /============|============|============|============|============|
    #
    #               2nd swath    4th swath    6th swath
    #            |------------|------------|------------|------------|
    #            |.....|
    #            overlap
    #
    #            +     ******* 1
    #             +   *
    #              + *
    #               *            weights (+) previous swath, (*) current swath
    #              * +
    #             *   +
    #            *     +++++++ 0

    bins = np.linspace(xlow, xhigh, 2 * nbin + 1)  # boundaries of bins
    ibeg_half = np.ceil(bins[:-2]).astype(int)  # beginning of each bin
    iend_half = np.floor(bins[2:]).astype(int)  # end of each bin
    bincen = 0.5 * (ibeg_half + iend_half)  # center of each bin

    # Perform slit decomposition within each swath stepping through the order with
    # half swath width. Spectra for each decomposition are combined with linear weights.
    for ihalf in range(0, 2 * nbin - 1):  # loop through swaths
        ib = ibeg_half[ihalf]  # left column
        ie = iend_half[ihalf] + 1  # right column
        nc = ie - ib  # number of columns in swath

        # Weight for combining overlapping regions
        weight = np.ones(nc)
        if ihalf > 0:
            weight[: nc // 2 + 1] = np.arange(nc // 2 + 1) / nc * 2
        oweight = 1 - weight

        # Cut out swath from image
        index = make_index(yc - ylow, yc + yhigh, ib, ie)
        sf = img[index]

        # Telluric
        if telluric:
            tel_lim = (
                telluric if telluric > 5 and telluric < nysf / 2 else min(5, nysf / 3)
            )
            tel = np.sum(sf, axis=0)
            itel = np.arange(nysf)
            itel = itel[np.abs(itel - nysf / 2) >= tel_lim]
            tel = sf[itel, :]
            sc = np.zeros(nc)

            for itel in range(nc):
                sc[itel] = np.median(tel[itel])

            tell = sc
        else:
            tell = 0

        if not no_scatter:
            # y indices
            index_y = np.array([np.arange(k, nysf + k) for k in yc[ib:ie] - yslitf[0]])
            dy_scatter = (index_y.T - yscatter_below[None, ib:ie]) / (
                yscatter_above[None, ib:ie] - yscatter_below[None, ib:ie]
            )
            scatter = (
                scatter_above[None, ib:ie] - scatter_below[None, ib:ie]
            ) * dy_scatter + scatter_below[None, ib:ie]
        else:
            scatter = 0

        # Do Slitfunction extraction
        sf -= scatter + tell
        sf = np.clip(sf, 0, None)

        # offset from the central line
        y_offset = ycen[ib:ie] - yc[ib:ie]
        if use_2d:
            sp, sfsm, model, unc = slitfunc_curved(
                sf,
                y_offset,
                tilt,
                lambda_sp=lambda_sp,
                lambda_sl=lambda_sf,
                osample=osample,
            )
            delta_x = None  # TODO get this from slitfunc_curved
        else:
            sp, sfsm, model, unc = slitfunc(
                sf, y_offset, lambda_sp=lambda_sp, lambda_sf=lambda_sf, osample=osample
            )

        if normalize:
            # In case we do FF normalization replace the original image by the
            # ratio of sf/sfbin where number of counts is larger than threshold
            # and with 1 elsewhere
            scale = 1

            ii = np.where(model > threshold / gain)
            sss = np.ones((nysf, nc))
            ddd = np.copy(model)
            sss[ii] = sf[ii] / model[ii]

            if ihalf > 0:
                overlap = iend_half[ihalf - 1] - ibeg_half[ihalf] + 1
                sss[ii] /= scale
                sp *= scale
            else:
                nc_old = nc
                sss_old = np.zeros((nysf, nc))
                ddd_old = np.zeros((nysf, nc))
                overlap = ibeg_half[1] - ibeg_half[0]

            # Combine new and old sections
            ncc = overlap

            index = make_index(yc + yslitf[0], yc + yslitf[1], ib, ib + ncc)
            im_norm[index] = (
                sss_old[:, -ncc:] * oweight[:ncc] + sss[:, :ncc] * weight[:ncc]
            )
            im_ordr[index] = (
                ddd_old[:, -ncc:] * oweight[:ncc] + ddd[:, :ncc] * weight[:ncc]
            )

            if ihalf == 2 * nbin - 2:
                # TODO check
                index = make_index(yc + yslitf[0], yc + yslitf[1], ib + ncc, ib + nc)
                im_norm[index] = sss[:, ncc:nc]
                im_ordr[index] = ddd[:, ncc:nc]

            nc_old = nc
            sss_old = np.copy(sss)
            ddd_old = np.copy(ddd)

        # Combine overlaping regions
        if use_2d:
            if ihalf > 0 and ihalf < 2 * nbin - 2:
                spec[ib + delta_x : ie - delta_x] = (
                    spec[ib + delta_x : ie - delta_x] * oweight[delta_x : nc - delta_x]
                    + sp[delta_x:-delta_x] * weight[delta_x:-delta_x]
                )
            elif ihalf == 0:
                spec[ib : ie - delta_x] = sp[:-delta_x]
            elif ihalf == 2 * nbin - 2:
                spec[ib + delta_x : ie] = (
                    spec[ib + delta_x : ie] * oweight[delta_x:-1]
                    + sp[delta_x:-1] * weight[delta_x:-1]
                )
        else:
            spec[ib:ie] = spec[ib:ie] * oweight + sp * weight

        sunc[ib:ie] = sunc[ib:ie] * oweight + unc * weight

        if plot:
            # TODO make this nice
            plt.clf()
            scale = 1
            pscale = np.mean(sp)
            sfplot = gaussian_filter1d(sfsm, osample)
            sfflat = sfsm[:-2] * pscale
            model = np.mean(model, axis=1)
            if not no_scatter:
                poffset = np.mean(scatter_below[ib:ie] + scatter_above[ib:ie]) * 0.5
            else:
                poffset = 0

            # Plot 1: The observed slit
            plt.subplot(221)
            plt.title("Order %i, Columns %i through %i" % (ord_num, ib, ie))
            # plt.plot(sfflat)
            # plt.plot(ysfpnt[jbad], sfpnt[jbad] * pscale, "g+")
            plt.plot(sfflat, "+")
            plt.plot(model)

            # Plot 2: The recovered slit function
            plt.subplot(222)
            plt.title("Order %i, Columns %i through %i" % (ord_num, ib, ie))
            plt.plot(model)
            # plt.plot(ysfpnt[jbad], sfpnt[jbad] * pscale, "g+")
            # plt.plot(sfplot)

            # Plot 3: Difference between observed and recovered
            plt.subplot(223)
            plt.title("Data - Fit")
            plt.plot(sfflat - model)
            # plt.plot(ysfpnt[jbad], (sfpnt - sfsm2)[jbad] * pscale, "g+")
            plt.plot(np.sqrt((model + poffset + readn ** 2) / gain))
            plt.plot(-np.sqrt((model + poffset + readn ** 2) / gain))

            plt.subplot(224)
            plt.title("Data - Fit")
            plt.plot(sfflat - model)
            # plt.plot(ysfpnt[jbad], (sf.flat - sfsm.flat)[jbad] * pscale, "g+")
            plt.plot(np.sqrt((model + poffset + readn ** 2) / gain))
            plt.plot(-np.sqrt((model + poffset + readn ** 2) / gain))

            plt.draw()
            plt.pause(0.001)

    # TODO ????? is that really correct
    sunc = np.sqrt(sunc + spec)

    # TODO what to return ?
    slitf = np.mean(slitf, axis=0)
    model = spec[:, None] * slitf[None, :]
    return spec, slitf, model, sunc
Beispiel #10
0
def getarc(img, orders, onum, awid, x_left_lim=0, x_right_lim=-1):
    """
    # This subroutine extracts a curved arc (arc) from an image array (im). The
    #   curvature of the arc is determined from polynomial fit coefficients (orc)
    #   which usually trace the curvature of the echelle orders. The particular
    #   arc to extract is specified by an order number (onum), which need not be
    #   integral. Positions of nonintegral orders are interpolated from surrounding
    #   orders.
    # im (input array (# columns , # rows)) image from which to extract arc.
    # orc (input array (# of coeff per fit , # of orders)) coefficients from PIT
    #   fit of column number versus row number (of echelle orders, usually). The
    #   polynomials trace arcs (orders, usually) indexed by order number, begining
    #   with zero closest to row zero and increasing as row number increases.
    #   **Note**  These are the extended order coefficients.
    # onum (input scalar) order number of arc to extract - need not be integral.
    # awid (input scalar) full width of arc to be extracted.
    #   Two specifications are possible:
    #     max(awid) <= 1, awid is fraction of the local distance between orders to mash.
    #     max(awid) >  1, awid is the specific number of pixels to mash.
    # arc (output vector (# columns)) counts PER PIXEL in arc extracted from image.
    # [pix (output vector (# columns)] returns the fractional number of pixels
    #   mashed in each column to make arc.
    # 29-Nov-91 GB translated from ANA
    # 22-Dec-91 GB made to return zeros if arc off image
    # 05-Jul-94 JAV, CMJ Moved endelse to extract full arc instead of half when
    #           fraction of an arc is specified
    """

    # ncol, nrow = img.shape
    i1, i2 = x_left_lim, x_right_lim
    # if(keyword_set(x_left_lim )) then i1 = x_left_lim  else i1 = 0
    # if(keyword_set(x_right_lim)) then i2 = x_right_lim else i2 = ncol-1

    # Define useful quantities
    # ncol = len(img[0, i1:i2])  # number of columns
    nrow = len(img[:, i1])  # number of rows
    ix = np.arange(i1, i2, 1, dtype=float)  # vector of column indicies
    arc = np.zeros_like(ix)  # dimension arc vector
    pix = 1.0  # define in case of trouble

    # Interpolate polynomial coefficients for surrounding orders to get polynomial
    # coefficients.  Note that this is mathematically equivalent to interpolating
    # the column indicies for surrounding orders, since the column indicies are
    # linear functions of the polynomial coefficients. However, interpolating
    # coefficients should be faster.

    if np.max(awid) < 1:  # awid is an order fraction
        ob = onum - awid / 2  # order # of bottom edge of arc
        obi = int(ob)  # next lowest integral order #A
        cb = orders[obi] + (ob - obi) * (orders[obi + 1] - orders[obi])
        yb = np.polyval(cb, ix)  # row # of bottom edge of swath

        ot = onum + awid / 2  # order # of top edge of arc
        oti = int(ot)  # next lowest integral order #
        ct = orders[oti] + (ot - oti) * (orders[oti + 1] - orders[oti])
        yt = np.polyval(ct, ix)  # row # of top edge of swath

    else:  # awid is number of pixels
        c = np.copy(orders[onum])
        yb = np.polyval(c, ix) - awid / 2  # row # of bottom edge of swath
        yt = np.polyval(c, ix) + awid / 2  # row # of top edge of swath

    if np.min(yb) < 0:  # check if arc is off bottom
        raise Exception(
            "FORDS: Warning - requested arc is below bottom of image. %i" % onum
        )
    if np.max(yt) > nrow:  # check if arc is off top of im
        raise Exception(
            "FORDS: Warning - requested arc is above top of image. %i" % onum
        )

    diff = np.round(np.mean(yt - yb) * 0.5)
    yb = np.clip(np.round((yb + yt) * 0.5 - diff), 0, None).astype(int)
    yt = np.clip(np.round((yb + yt) * 0.5 + diff), None, nrow).astype(int)

    # Define the indices for the pixels
    # in x: the rows between yb and yt
    # in y: the column, but n times to match the x index
    index = make_index(yb, yt, i1, i2, zero=True)
    # Sum over the prepared index
    arc = np.sum(img[index], axis=0)

    return arc, pix