eff_dualbeam.py 9.6 KB
title = "Dualbeam"
tip = "transforms dual beam maps to given coordinate system"
onein = True

import numpy as np
import nodastro
from nodmath import FixNaNs
#from scipy.ndimage import map_coordinates
from nodmath import map_interpolate
try:
   from scipy.interpolate import griddata
except:
   from nodmath import griddata
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 _

RAD = np.pi/180.0

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 compute_app(self, **args):
        class FuncParam(DataSet):
            descript = BoolItem("Descriptive", default=True)
        name = title.replace(" ", "")
        if args == {}:
           param = FuncParam(_(title), "Transform in descriptive coordinate system:")
        else:
           param = self.parent.ScriptParameter(name, args)

        # if no parameter needed set param to None. activate next line
        param = None
        self.parent.compute_11(name, lambda m, p: self.function(m, p), param, onein) 

    def trafo(self, mat):
        return lambda x, y: self.na.getCoord(x, y, mat)

    def getAzEl(self, phi):
        return lambda x, y: self.na.azel(phi, x, y)

    def matrix(self, ra, dec, epoch, desc):
        if epoch == 2000:
           pmat = self.na.adnow2000
        elif epoch == 1950:
           pmat = self.na.adnow1950
        else:
           txt = str("Epoch of %d not yet defined" % epoch)
           self.Error(txt)
           return [], None
        rmat = self.na.rotmat(ra, dec, 0.0)
        if desc:
           return np.dot(pmat.T, rmat)
        else:
           return pmat.T

    def radec2azel(self, m, p_descript):
        na = self.na
        epoch = int(m.header['EPOCH']+0.5)
        phi = m.header['SITELAT']
        RA = m.header['CRVAL1']
        DEC = m.header['CRVAL2']
        dAz = m.header['PATLONG']
        dEl = m.header['PATLAT']
        xpix = m.header['CRPIX1']-1
        ypix = m.header['CRPIX2']-1
        dxpix = abs(m.header['CDELT1'])
        dypix = m.header['CDELT2']
        sid = m.sidmap.ravel()

        # calculate new sidereal time and eqatorial coordinates from horizontal
        pmat = self.matrix(RA, DEC, epoch, False)
        mat = self.matrix(RA, DEC, epoch, p_descript) 
        ra_apcent, dec_apcent = na.trafo(RA, DEC, pmat)
        if p_descript:
           Mat = na.rotmat(ra_apcent, dec_apcent, 0.0)
        else:
           Mat = np.array(na.unit)
        py, px = np.indices(m.data.shape)
        ddec, dra = (py.ravel()-ypix)*dypix, -(px.ravel()-xpix)*dxpix
        # apparent position absolut
        r_ap, d_ap = self.trafo(mat)(*np.array([dra, ddec]))
        az, el = self.getAzEl(phi)(*np.array([sid-r_ap, d_ap])) 
        az_center, el_center = self.getAzEl(phi)(*np.array([sid-ra_apcent, 0*sid+dec_apcent]))
        Az, El = (az-az_center)*np.cos(RAD*el), el-el_center
        y, x = (El-np.nanmin(El))/dypix, (Az-np.nanmin(Az))/dxpix
        newcols = nint(abs(np.nanmax(Az)-np.nanmin(Az))/dxpix)+1
        newrows = nint(abs(np.nanmax(El)-np.nanmin(El))/dypix)+1
        grid_y, grid_x = np.indices((newrows, newcols))
        newsid = griddata((y, x), sid, (grid_y, grid_x), method='nearest')
        sid = newsid.ravel()

        rows, cols = np.indices((newrows, newcols))
        newypix, newxpix = -np.nanmin(El)/dypix, -np.nanmin(Az)/dxpix 
        El, Az = (rows.ravel()-newypix)*dypix, (cols.ravel()-newxpix)*dxpix
        az_center, el_center = self.getAzEl(phi)(*np.array([sid-ra_apcent, 0*sid+dec_apcent]))
        el = el_center + El
        az = az_center + Az/np.cos(RAD*el)
        t, d = self.getAzEl(phi)(*np.array([az, el]))
        ra, dec = self.trafo(mat.T)(*np.array([sid-t, d]))
        px = xpix - ra/dxpix
        py = ypix + dec/dypix

        # interpolation
        #m.data = FixNaNs(m.data)
        #m.data = map_coordinates(m.data, (py, px), order=4, mode='constant',
        #                         cval=np.nan, prefilter=True, output=np.float32)
        m.data = map_interpolate(m.data, px, py)
        m.data = m.data.reshape((newrows, newcols))
        m.sidmap = sid.reshape((newrows, newcols)) #*240.0
         
        m.header['PATLONG'] = 0.0
        m.header['PATLAT'] = 0.0
        m.header['CDELT1'] = abs(m.header['CDELT1'])
        m.header['CRPIX1'] = newxpix+1 + dAz/m.header['CDELT1']
        m.header['CRPIX2'] = newypix+1
        m.header['CTYPE1'] = "RA---SFL"
        m.header['CTYPE2'] = "DEC--SFL"
        m.header['NAXIS1'] = newcols
        m.header['NAXIS2'] = newrows
        #m.header.set('SCANDIR', 'ALON')
        return m

    def azel2radec(self, m, p_descript):
        na = self.na
        epoch = int(m.header['EPOCH']+0.5)
        phi = m.header['SITELAT']
        RA = m.header['CRVAL1']
        DEC = m.header['CRVAL2']
        dAz = m.header['PATLONG']
        dEl = m.header['PATLAT']
        xpix = m.header['CRPIX1']-1
        ypix = m.header['CRPIX2']-1
        dxpix = m.header['CDELT1']
        dypix = m.header['CDELT2']
        sid = m.sidmap.ravel()

        # calculate new sidereal time and eqatorial coordinates from horizontal
        pmat = self.matrix(RA, DEC, epoch, False) 
        mat = self.matrix(RA, DEC, epoch, p_descript) 
        ra_apcent, dec_apcent = na.trafo(RA, DEC, pmat)
        if p_descript:
           Mat = na.rotmat(ra_apcent, dec_apcent, 0.0)
        else:
           Mat = np.array(na.unit)
        az_center, el_center = self.getAzEl(phi)(*np.array([sid - ra_apcent, 0*sid+dec_apcent]))
        py, px = np.indices(m.data.shape)
        el = (py.ravel()-ypix)*dypix + el_center - dEl
        az = (px.ravel()-xpix)*dxpix/np.cos(RAD*el) + az_center - dAz
        t, d = self.getAzEl(phi)(*np.array([az, el]))
        # apparent position descriptive or absolut
        ra, dec = self.trafo(Mat.T)(*np.array([sid-t, d]))
        y, x = (dec-np.nanmin(dec))/dypix, (np.nanmax(ra)-ra)/dxpix
        # catalog position descriptive or absolut
        ra, dec = self.trafo(mat.T)(*np.array([sid-t, d]))
        newcols = nint(abs(np.nanmax(ra)-np.nanmin(ra))/dxpix)+1
        newrows = nint(abs(np.nanmax(dec)-np.nanmin(dec))/dypix)+1
        grid_y, grid_x = np.indices((newrows, newcols))
        #m.data = griddata((y, x), m.data.ravel(), (grid_y, grid_x), method='cubic')
        #return m, p
        newsid = griddata((y, x), sid, (grid_y, grid_x), method='nearest')
        sid = newsid.ravel()
         
        rows, cols = np.indices((newrows, newcols))
        newypix, newxpix = -np.nanmin(dec)/dypix, np.nanmax(ra)/dxpix
        ddec = (rows.ravel()-newypix)*dypix
        dra = -(cols.ravel()-newxpix)*dxpix
        if p_descript:
           r, d = self.trafo(mat)(*np.array([dra, ddec]))
        else:
           r, d = self.trafo(mat)(*np.array([ra+dra, dec+ddec]))
        az, el = self.getAzEl(phi)(*np.array([sid-r, d]))
        ac, ec = self.getAzEl(phi)(*np.array([sid-ra_apcent, 0*d+dec_apcent]))
        px = xpix + (az-ac+dAz)/dxpix*np.cos(RAD*el)
        py = ypix + (el-ec+dEl)/dypix

        # interpolation
        #m.data = FixNaNs(m.data)
        #m.data = map_coordinates(m.data, (py, px), order=4, mode='constant',
        #                         cval=np.nan, prefilter=True, output=np.float32)
        m.data = map_interpolate(m.data, px, py)
        m.data = m.data.reshape((newrows, newcols))
        m.sidmap = sid.reshape((newrows, newcols))*240.0
         
        m.header['PATLONG'] = 0.0
        m.header['PATLAT'] = 0.0
        m.header['CDELT1'] = -abs(m.header['CDELT1'])
        m.header['CRPIX1'] = newxpix+1
        m.header['CRPIX2'] = newypix+1
        m.header['NAXIS1'] = newcols
        m.header['NAXIS2'] = newrows
        if p_descript:
           m.header['CTYPE1'] = "RA---DES"
           m.header['CTYPE2'] = "DEC--DES"
        else:
           m.header['CTYPE1'] = "RA---CAR"
           m.header['CTYPE2'] = "DEC--CAR"
        #del m.header['SCANDIR']
        return m

    def function(self, m, p):
        if p == None:
           p_descript = True
        else:
           p_descript = p.descript
        na = nodastro.nodtrafo(m.header['DATE_OBS'])
        self.na = na
        if m.header['CTYPE1'][:4] == "GLON":
           self.gmat = na.LBAD2000
        elif int(m.header['EPOCH']+0.5) != 1950 and int(m.header['EPOCH']+0.5) != 2000:
           self.Error("Map not in J2000 or B1950")
           return [], None
        else:
           self.gmat = na.unit
        # rescale sidmap 
        if 'SIDPIX' in m.header.keys():
           dx = m.header['SIDPIX']
           ix = nint(dx+0.5)
        else: 
           ix = 0
        if not hasattr(m, 'sidmap'):
           self.Error("sorry, no sidereal time data available")
           return [], None
        m.sidmap = m.sidmap[:,:m.sidmap.shape[1]-ix+1]/240.0
        if not 'PATLONG' in m.header.keys():
           self.Error("PATLONG not defined,  no transformation necessary!")
           return [], None 
        elif m.header['PATLONG'] == 0.0:
           self.Error("PATLONG == 0.0,  no transformation necessary!")
           return [], None 
        elif 'SCANDIR' in m.header.keys() and m.header['SCANDIR'] not in ('ALON', 'ALAT'):
           m = self.radec2azel(m, p_descript)
           m = self.azel2radec(m, p_descript)
        else:
           self.Error("Map scanned in Az/El")
           return [], None
        m = self.parent.removeNANedges(m)
        self.parent.SidOut = True
        return m, p