pol_polden.py 8.97 KB
title = "PolInt"
tip = "best of all"
onein = 2

import numpy as np
import copy as cp
#import scipy.signal as sps
from scipy.ndimage.filters import median_filter, uniform_filter
from scipy.interpolate import InterpolatedUnivariateSpline

from guiqwt import pyplot
from guidata.qt.QtGui import QMessageBox
from guidata.dataset.datatypes import DataSet
from guidata.dataset.dataitems import (IntItem, StringItem, ChoiceItem, FloatItem, BoolItem)
from guiqwt.config import _

from nodmath import nan_interpolation, plotPDF
 
try:
   from nodfitting import curve_fit
except:
   from scipy.optimize import curve_fit

def nint(x):
    if x > 0: return int(x+0.5)
    else: return int(x-0.5)

class NOD3_App:

    def __init__(self, parent):
        self.parent = parent
        self.parent.activateWindow()

    def Error(self, msg):
        QMessageBox.critical(self.parent.parent(), title,
                              _(u"Error:")+"\n%s" % str(msg))

    def Warning(self, msg):
        QMessageBox.critical(self.parent.parent(), title,
                              _(u"Warning:")+"\n%s" % str(msg))

    def compute_app(self, **args):
        class FuncParam(DataSet):
              size = IntItem('Size:', min=3, default=5)
	      frms = FloatItem('Factor of RMS:', min=0.0, max=10.0, default=2.0)
              #median = BoolItem("Median:", default=True)
              #error = BoolItem("ErrMap:", default=False)
        name = title.replace(" ", "")
        if args == {}:
           param = FuncParam(_(title), "Size of median box:")
        else:
           param = self.parent.ScriptParameter(name, args)

        # if no parameter needed set param to None. activate next line
        #param = None
        self.name = name
        #self.parent.compute_11(name, lambda m, p: self.function(m, p), param, onein, extern=True) 
        if 'BMAJ' in self.parent.item.header:
           size = max(5, nint(abs(self.parent.item.header['BMAJ']/self.parent.item.header['CDELT1'])))
        else:
           size = 5
        size = str("size=%d" % size)
        self.parent.compute_11(name, lambda m, p: self.function(m, p), param, onein, extern=False, setpar=size) 

    def smooth_sharpen(self, data, window=5, alpha=30):
        from scipy.ndimage.filters import gaussian_filter
        blurred = gaussian_filter(data, sigma=(window,window))
        filter_blurred = gaussian_filter(blurred, 1)
        sharpened = blurred + alpha * (blurred - filter_blurred)
        return sharpened

    def mod_median1(self, U, Q, size):
        x = 1*Q
        y = 1*U
        mask = np.ones((size, size))
        if size%2:
           mask[(size-1)/2][(size-1)/2] = 0
        else:
           mask[(size-1)/2][(size-1)/2] = 1
        try:
           xm = median_filter(x, footprint=mask)
           ym = median_filter(y, footprint=mask)
        except:
           xm = median_filter(x, size=(size, size))
           ym = median_filter(y, size=(size, size))
        xm1 = median_filter(x, size=(size, size))
        ym1 = median_filter(y, size=(size, size))
        return np.arctan2((2*ym+ym1)/3, (2*xm+xm1)/3)

    def mod_median(self, angle, size):
        x = np.cos(angle)
        y = np.sin(angle)
        mask = np.ones((size, size))
        if size%2:
           mask[(size-1)/2][(size-1)/2] = 0
        else:
           mask[(size-1)/2][(size-1)/2] = 1
        try:
           xm = median_filter(x, footprint=mask)
           ym = median_filter(y, footprint=mask)
        except:
           xm = median_filter(x, size=(size, size))
           ym = median_filter(y, size=(size, size))
        xm1 = median_filter(x, size=(size, size))
        ym1 = median_filter(y, size=(size, size))
        #xm1 = uniform_filter(x, size=(size, size))
        #ym1 = uniform_filter(y, size=(size, size))
        return np.arctan2((2*ym+ym1)/3, (2*xm+xm1)/3)
        #return np.arctan2(ym1, xm1)
        #return np.arctan2(ym, xm)

    def mod_mean(self, angle, size):
        x = np.cos(angle)
        y = np.sin(angle)
        xm = uniform_filter(x, size=size)
        ym = uniform_filter(y, size=size)
        f0 = 2./3.
        fac = f0 / float(size)**2
        fac /= (float(size)/5.0)**2
        xc = x*fac
        yc = y*fac
        return np.arctan2(ym-yc, xm-xc)

    def plot(self, xy, lh, x0, txt, std, fitonly=False):
        def gauss(X, a, x0, dx, off, slope):
            x = X - dx
            #return off + slope*x + a*np.exp(-(x*x)/(2*x0*x0))
            return a*np.exp(-(x*x)/(2*x0*x0))

        def fit(f, x, y, p0):
            xtol = 1.49012e-08
            Error = True
            i0 = np.argmax(y)
            y = list(y)
            x = list(x)
            x.pop(i0)
            y.pop(i0)
            x = np.array(x)
            y = np.array(y)
            while Error:
                  try:
                     results = curve_fit(f, x, y, p0=p0, xtol=xtol)
                     popt = results[0]
                     Error = False
                  except:
                     Error = True
                     xtol *= 2.0
                     if xtol > 1.0:
                        return 0.0
            return popt

        x = xy[1][:lh]
        y = xy[0][:lh]
        rms = None
        p0 = (max(y), std/2, 0.0, 0.0, 0.0)
        popt = fit(gauss, x, y, p0)
        if popt != []:
           rms = abs(popt[1])
           off = popt[2]
        if fitonly:
           return rms
        self.parent.fig = pyplot.figure("PI noise distribution")
        if txt != "": pyplot.legend()
        if rms != None:
           pyplot.plot(x, y, "b*", label=txt)
           pyplot.plot(x, gauss(x, *popt), "r-", label=str("RMS=%.2f" % rms))
           pyplot.plot(x, gauss(x, *popt), "", label=str("Off=%.2f" % off))
	else:
           pyplot.plot(x, y, "b-", label=txt)
        pyplot.xlabel("Intensity")
        pyplot.ylabel("#bins")
        pyplot.zlabel("distribution")
        pyplot.show(mainloop=False)
        return rms

    def histo(self, U, Q, pang):
        pa = np.arctan2(U, Q)
        hdata = np.sin(pa-pang) * np.sqrt(U*U + Q*Q)
        self.errordata = 1*hdata
        ny, nx = hdata.shape
        mask = ~np.isnan(hdata)
        hdata = hdata[mask]
        #med = max(2*np.median(hdata), 2*abs(hdata.min()))
        med = abs(np.nanmin(hdata))
        for i in range(3):
            bins = min(int(np.sqrt(nx*ny)), 32)
            hdata = np.where(abs(hdata) < med, hdata, med)
            hist, bin_edges = np.histogram(hdata, bins=bins)
            dbin = bin_edges[1] - bin_edges[0]
            #hist /= dbin
            bin_edges += dbin/2.0
            hist = hist[1:]
            bin_edges = bin_edges[1:-1]
            #bin_edges = bin_edges[:-1]
            lh = len(hist)
            for i in range(len(hist)):
                if abs(bin_edges[i]) < med: lh = i
            hmax = 0.0
            imax = 0
            txt = "dPI"
            for i in range(lh):
                if hist[i] > imax:
                   hmax = bin_edges[i]
                   imax = hist[i]
            med = self.plot([hist, bin_edges], lh, hmax, txt, np.std(hdata), fitonly=True) * 5
        rms = self.plot([hist, bin_edges], lh, hmax, txt, np.std(hdata))
        return round(rms, 5)

    def function(self, ms, p):
        if not hasattr(p, 'median'):
           p.median = True
        if not hasattr(p, 'error'):
           p.error = False
        for m in ms:
            if m.header["MAPTYPE"] == "U":
               maskU = ~np.isnan(m.data)
               U = nan_interpolation(m.data)
            elif m.header["MAPTYPE"] == "Q":
               maskQ = ~np.isnan(m.data)
               Q = nan_interpolation(m.data) 
            else:
               return [], p
        mask = maskU * maskQ
        #try: size = max(5, int(m.header['BMAJ']/m.header['CDELT2']+1))
        #except: size = max(3, p.size + (p.size+1)%2)
        #size = max(3, p.size + (p.size+1)%2)
        size = max(3, p.size)
        if p.median:
           pang = self.mod_median(np.arctan2(U, Q), size) 
           #pang = self.mod_median1(U, Q, size) 
        else:
           pang = self.mod_mean(np.arctan2(U, Q), size) 
        m.data = U*np.sin(pang) + Q*np.cos(pang)
        rms = self.histo(U, Q, pang)
        m.header["MAPTYPE"] = 'PI'
        if 'EXTNAME' in m.header:
           extname = m.header['EXTNAME'].replace("Q", 'PI').replace("U", 'PI')
        else:
           extname = "MAP-PI"
        m.header["EXTNAME"] = extname
        m.header["PSIG"] = (rms, "RMS of polarized intensity")
        m.header["MEDIAN"] = (size, "Median window size")
	mpa = cp.deepcopy(m)
	mpa.header['EXTNAME'] = 'MAP-PA'
        mpa.header["MAPTYPE"] = 'PA'
	mer = cp.deepcopy(m)
	mer.header['EXTNAME'] = 'MAP-PI-Error'
        mer.header["MAPTYPE"] = 'PError'
        adata = pang * 90.0/np.pi #+ 90.0
	mpa.data = np.where(np.abs(m.data) > p.frms*rms, adata, np.nan)
        m.data = np.where(mask, m.data, np.nan)
        mpa.data = np.where(mask, mpa.data, np.nan)
	mer.data = np.where(mask, self.errordata, np.nan)
        if p.error:
           plotPDF(mer.data, self.parent.cmap, self.parent.Outliers, rebin=1)
           return [mer, mpa, m], p
        else:
           return [mpa, m], p