nodastro.py 10.7 KB
import numpy as np
import novas
import time

RAD = np.pi/180.0
GRD = 180.0/np.pi

class nodtrafo:

    def __init__(self, JD=None):

        if JD == None:
           JD = self.JulDat()
        else:
           JD = self.str_JD(JD)
        epsm, eps, eqeq, dpsi, deps = novas.etilt(JD)
        self.eps = eps
        self.JD = JD

        # old nod2 matrix
        self.LBAD2000 = [[-0.0548777625376,  0.4941083214789, -0.8676666398013], \
                         [-0.8734369590694, -0.4448308611625, -0.1980741868317], \
                         [-0.4838350025685,  0.7469822431643,  0.4559837921317]]
        self.lbad2000 = [[-0.054875539,  0.494109454, -0.867666136], \
                         [-0.873437105, -0.444829594, -0.198076390], \
                         [-0.483834992,  0.746982249,  0.455983795]]
        # old nod2 matrix
        self.AD50AD00 = [[ 0.9999257079524, -0.0111789381378, -0.0048590038154], \
                         [ 0.0111789381264,  0.9999375133500, -0.0000271625947],
                         [ 0.0048590038415, -0.0000271579263,  0.9999881946024]]
        self.ad50ad00 = [[ 0.9999256782, -0.0111820611, -0.0048579477], \
                         [ 0.0111820610,  0.9999374784, -0.0000271765],
                         [ 0.0048579479, -0.0000271474,  0.9999881997]]
        self.ekad2000 = [[ 1.0000000000000,  0.0000000000000,  0.0000000000000], \
                         [ 0.0000000000000,  0.9174820583615, -0.3977771644837], \
                         [ 0.0000000000000,  0.3977771644837,  0.9174820583615]]
        self.ekadnow  = [[ 1.0,  0.0,  0.0], \
                         [ 0.0,  np.cos(eps*RAD), -np.sin(eps*RAD)], \
                         [ 0.0,  np.sin(eps*RAD),  np.cos(eps*RAD)]]
        self.unit = [[1.0, 0.0, 0.0], \
                     [0.0, 1.0, 0.0], \
                     [0.0, 0.0, 1.0]]
        self.lbad1950 = np.dot(np.array(self.ad50ad00).transpose(), self.lbad2000)
        self.adnow2000 = self.premat(JD, 2451545.0)
        self.adnow1950 = self.premat(JD, 2433282.4235)

    def azel(self, phi, az, el):
        x = np.sin(el*RAD)*np.cos(phi*RAD) - np.cos(el*RAD)*np.cos(az*RAD)*np.sin(phi*RAD)
        y = -np.cos(el*RAD)*np.sin(az*RAD)
        z = np.sin(el*RAD)*np.sin(phi*RAD) + np.cos(el*RAD)*np.cos(az*RAD)*np.cos(phi*RAD)
        stw = np.arctan2(y,x)*GRD
        delta = np.arctan2(z, np.sqrt(x*x+y*y))*GRD
        return stw, delta

    def horizon2equator(self, phi):
        sinphi = np.sin(phi*RAD)
        cosphi = np.cos(phi*RAD)
        mat = [[-sinphi, 0.0, cosphi], [0.0, -1.0, 0.0], [cosphi, 0.0, sinphi]]
        return np.array(mat)

    def sidereal(self, t):
        sint = np.sin(t*RAD)
        cost = np.cos(t*RAD)
        mat = [[cost, sint, 0.0], [sint, -cost, 0.0], [0.0, 0.0, 1.0]]
        return np.array(mat)

    def str_JD(self, date):
        if type(date) == float:
           ja = int(0.01*int(date))
           jy = int(date)
           days = (date - int(date)) * 365.25
           jd = int(365.25*jy) - 678576 - ja + int(0.25*ja) + days + 2400000.5
           return jd
        x = date.split("T")
        if len(x) == 1:
           t = time.strptime(date)
           year = t.tm_year
           month = t.tm_mon
           day = t.tm_mday
           hour = float(t.tm_hour) + float(t.tm_min)/60.0 + float(t.tm_sec)/3600.0
        else:
           day, month, year = x[0].split("-")
           if int(day) > 1000:
              y = day
              day = year
              year = y
           h, m, s = x[1].split(":")
           hour = float(h) + float(m)/60.0 + float(s)/3600.0
        jd = novas.juldat(int(year), int(month), int(day), hour)
        return jd

    def JulDat(self):

        """ calculates the Julian day from the computer time signal """

        jd = 2440587.5 + time.time() / 86400.0

        return jd


    def invert(self, mat):

        return mat.transpose()


    def get_trafo_matrix(self, coord_in, equinox_in, coord_out, equinox_out):
        
        """ Calculates coordinate transformation matix """

        c_in = coord_in.split("-")[0]
        c_out = coord_out.split("-")[0]
        if c_in[:2] == "GL" and c_out[:2] == "RA" and int(equinox_out) == 2000:
           return self.lbad2000
        elif c_in[:2] == "GL" and c_out[:2] == "RA" and int(equinox_out) == 1950:
           return self.lbad1950
        elif c_in[:2] == "RA" and int(equinox_in) == 2000 and c_out[:2] == "GL":
           return np.array(self.lbad2000).transpose()
        elif c_in[:2] == "RA" and int(equinox_in) == 1950 and c_out[:2] == "GL":
           return np.array(self.lbad1950).transpose()
        elif c_in[:2] == "RA" and int(equinox_in) == 2000 and \
             c_out[:2] == "RA" and int(equinox_out) == 1950:
           return np.array(self.ad50ad00).transpose()
        elif c_in[:2] == "RA" and int(equinox_in) == 1950 and \
             c_out[:2] == "RA" and int(equinox_out) == 2000:
           return self.ad50ad00
        elif c_in == c_out: 
           return self.unit
        else:
           return []


    def trafo(self, lam, bet, mat):
        x = np.cos(lam*RAD)*np.cos(bet*RAD)
        y = np.sin(lam*RAD)*np.cos(bet*RAD)
        z = np.sin(bet*RAD)
        x1, y1, z1 = np.dot(mat, (x,y,z))
        lam1 = np.arctan2(y1, x1)/RAD
        bet1 = np.arctan2(z1, np.sqrt(x1*x1+y1*y1))/RAD
        return lam1, bet1


    def premat(self, jd1, jd2):
    
        """ Computation of the precession matrix for transformations
        between the epochs "jd1" and "jd2".
        The coefficients in the precession angles are those given by J.H.Lieske
        et al., Astron.Astrophys. 58, 1-16, 1977, Table 5; they were accepted
        by the IAU as the present standard.
     
           jd1  = Jul.Date of given mean equator and equinox
           jd2  = Jul.Date of new mean equator and equinox
     
        precmat  = Matrix of precession from jd1 to jd2"""
    
        dczet = [2306.2181, 1.39656, 1.39e-4, 3.0188e-1, 3.44e-4, 1.7998e-2]
        dcztt = [7.928e-1, 4.1e-4, 2.05e-4]
        dcthe = [2004.3109, 8.533e-1, 2.17e-4, 4.2665e-1, 2.17e-4, 4.1833e-2]
        dcj20c = 2451545.0
        dcjcen = 36525.0
        dcsar = np.pi/(180.0*3600.0)
        
        t0 = (jd1-dcj20c)/dcjcen
        t = (jd2-jd1)/dcjcen
        t0sq = t0*t0
        tsq = t*t
        tcb = tsq*t
        zeta = ((dczet[0]+t0*dczet[1]-t0sq*dczet[2])*t \
            +(dczet[3]-t0*dczet[4])*tsq +tcb*dczet[5])*dcsar
        zett = zeta+((dcztt[0]+t0*dcztt[1])*tsq +tcb*dcztt[2])*dcsar
        thet = ((dcthe[0]-t0*dcthe[1]-t0sq*dcthe[2])*t \
            -(dcthe[3] +t0*dcthe[4])*tsq -tcb*dcthe[5])*dcsar
        szeta = np.sin(zeta)
        czeta = np.cos(zeta)
        szett = np.sin(zett)
        czett = np.cos(zett)
        sthet = np.sin(thet)
        cthet = np.cos(thet)
        a = szeta*szett
        b = czeta*szett
        c = szeta*czett
        d = czeta*czett
    
        # and save it in the precession matrix
        premat  =  []
        premat.append(+d*cthet - a)
        premat.append(-c*cthet - b)
        premat.append(-sthet*czett)
        premat.append(+b*cthet + c)
        premat.append(-a*cthet + d)
        premat.append(-sthet*szett)
        premat.append(+czeta*sthet)
        premat.append(-szeta*sthet)
        premat.append(cthet)
    
        return np.reshape(premat, (3,3))
    
    
    def rotmat(self, l, b, a):
    
        """ this subroutine calculates the rotation matrix

               l = longitude of origin
               b = latitude of origin
               a = tilt angle 

            rotmat = Matrix of rotation"""

        zrot = [[np.cos(l*RAD), -np.sin(l*RAD), 0.0], \
                [np.sin(l*RAD), np.cos(l*RAD), 0.0], \
                [0.0, 0.0, 1.0]]
        yrot = [[np.cos(b*RAD), 0.0, -np.sin(b*RAD)], \
                [0.0, 1.0, 0.0], \
                [np.sin(b*RAD), 0.0, np.cos(b*RAD)]]
        xrot = [[1.0, 0.0, 0.0], \
                [0.0, np.cos(a*RAD), -np.sin(a*RAD)], \
                [0.0, np.sin(a*RAD), np.cos(a*RAD)]]

        return np.dot(np.dot(zrot, yrot), xrot)

    def rotmat_pst(self, l, b, a):
    
        """ this subroutine calculates the rotation matrix

               l = longitude of origin
               b = latitude of origin
               a = tilt angle 

            rotmat = Matrix of rotation"""

        cosl = np.cos(l*RAD)
        sinl = np.sin(l*RAD)
        cosb = np.cos(b*RAD)
        sinb = np.sin(b*RAD)
        cosa = np.cos(a*RAD)
        sina = np.sin(a*RAD)
    
        rotmat = []
        rotmat.append(cosb*cosl)
        rotmat.append(-sina*sinb*cosl - cosa*sinl)
        rotmat.append(-cosa*sinb*cosl + sina*sinl)
        rotmat.append(cosb*sinl)
        rotmat.append(-sina*sinb*sinl + cosa*cosl)
        rotmat.append(-cosa*sinb*sinl - sina*cosl)
        rotmat.append(sinb)
        rotmat.append(sina*cosb)
        rotmat.append(cosa*cosb)
    
        return np.reshape(rotmat, (3,3))


    def getCoord(self, l, b, mat):

        x = np.cos(RAD*b)*np.cos(RAD*l)
        y = np.cos(RAD*b)*np.sin(RAD*l)
        z = np.sin(RAD*b)

        xyz = np.dot(np.array(mat), np.array([x,y,z]))

        l1 = np.arctan2(xyz[1], xyz[0])
        b1 = np.arctan2(xyz[2], np.sqrt(xyz[1]**2 + xyz[0]**2))

        return l1/RAD, b1/RAD

 
    def getPosAng(self, l, b, rot, coord, equinox):

        if coord[:2] == "GL":
           mat = np.dot(self.lbad2000, self.adnow2000)
        elif int(equinox) == 1950:
           mat = self.adnow1950
        elif int(equinox) == 2000:
           mat = self.adnow2000
        else:
           return 0.0 
        mat = np.dot(mat, self.rotmat(0.0, 0.0, rot))
        ra_mean, dec_mean = self.getCoord(l, b, mat)
        ra = ra_mean*RAD
        dec = dec_mean*RAD

        sin_pos = mat[0][2]*np.sin(ra) - mat[1][2]*np.cos(ra)
        cos_pos = mat[0][2]*np.cos(ra) + mat[1][2]*np.sin(ra)
        cos_pos = -cos_pos*np.sin(dec) + mat[2][2]*np.cos(dec)
        pos = np.arctan2(sin_pos, cos_pos) * GRD

        return pos

    def Osmose(self, U, Q, FacU, FacQ, Angle):

        def parmat(p):
            return np.array([[np.cos(p), -np.sin(p)], [np.sin(p), np.cos(p)]])

        ly, lx = U.parmap.shape
        if 'CROTA2' in U.header: rot = U.header['CROTA2']
        else: rot = 0.0
        if 'EPOCH' in U.header: equinox = U.header['EPOCH']
        else: equinox = None
        coord = U.header['CTYPE1']
        for j in range(ly):
            b = U.header['CRVAL2'] + (j-U.header['CRPIX2'])*U.header['CDELT2']
            for i in range(lx):
                l = U.header['CRVAL1'] + (i-U.header['CRPIX1'])*U.header['CDELT1']
                omega = self.getPosAng(l, b, rot, coord, equinox)
                eta = (Angle -U.parmap[j][i] - omega)*RAD*2
                U.data[j][i], Q.data[j][i] = np.dot(parmat(eta),
                                             [FacU*U.data[j][i], FacQ*Q.data[j][i]])

        return U, Q