mambo5.py

'''
Author: Kristofer Drozd
Date: November 20, 2015


Description:
This python script performs calculations to obtain positional parameters (azi & zen) of the spacecraft and sun at the exact moment a picture is taken of the landmark being analyzed.

The following text files must be in the same directory in which the code is being run:
LMRKNAMES.txt: name of the landmark being analyzed
NUMBERPIC.txt: # of pictures taken of landmark
RESOLUTION.txt: resolution of each picture
PICTIMES.txt: UTC time of each picture
LAT.txt: latitude of landmark
LON.txt: west longitude of landmark
SCOBJ1.txt: x component of space craft to object center vectors (BF frame)
SCOBJ2.txt: y component of space craft to object center vectors (BF frame)
SCOBJ3.txt: z component of space craft to object center vectors (BF frame)
SZ1.txt: x component of object center to sun unit vectors (BF frame)
SZ2.txt: y component of object center to sun unit vectors (BF frame)
SZ3.txt: z component of object center to sun unit vectors (BF frame)
VLM1.txt: x component of object center to landmark vectors (BF frame)
VLM2.txt: y component of object center to landmark vectors (BF frame)
VLM3.txt: z component of object center to landmark vectors (BF frame)

Output:
A text file of the name <landmark name>_viewing.txt is created in the directory the code is run
'''

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches


def file_len(fname):
    '''
    This function counts the number of lines in a text file
    
    Parameters
    fname: name of the text file
    
    Returns
    i + 1: number of lines in the text file
    '''
    with open(fname) as f:
        for i, l in enumerate(f):
            pass

    return i + 1

def SCPOS(SCOBJ1, SCOBJ2, SCOBJ3):
    '''
    This function creates the object's center to spacecraft vector in body fixed frame. Since the SCOBJ compoents are from the spacecraft to the object's center, the components are multiplied by -1.
    
    Parameters
    SCOBJ1: x component of SCOBJ
    SCOBJ2: y component of SCOBJ
    SCOBGJ: z component of SCOBJ
    
    Returns
    SCOBJ: vector
    '''
    SCPOS = np.array([-SCOBJ1, -SCOBJ2, -SCOBJ3])

    return SCPOS

def SUNPOS(SZ1, SZ2, SZ3):
    '''
    This function creates the object center to sun vector in body fixed frame. Since SZ is a unit vector it is multuplied by 1 AU.
        
    Parameters
    SZ1: x component of SZ
    SZ2: y component of SZ
    SZ3: z component of SZ
        
    Returns
    SCOBJ: vector
    '''
    SZ_au = np.multiply(np.array([ SZ1, SZ2, SZ3]), 1.496e8)
    
    return SZ_au

def BEN2LMRK(VLM1, VLM2, VLM3):
    '''
    This function creates the object center to landmark vector in body fixed frame.
    
    Parameters
    VLM1: x component of BEN2LMRK
    VLM2: y component of BEN2LMRK
    VLM3: z component of BEN2LMRK
    
    Returns
    yomama: vector
    '''
    yomama = np.array([VLM1, VLM2, VLM3], float)

    return yomama
    
def BF2SEZ_tm(lon,lat):
    '''
    This function creates the Body Fixed frame to SEZ fram transformation matrix.
    
    Parameters
    lon: The east longitude of the landamrk (degrees)
    lat: The latitude of the landamrk (degreesP)
    
    Returns
    Qxx_mat: The transformation matrix
    '''
    lat_r = np.radians(lat)
    lon_r = np.radians(lon)
    Qxx_mat = np.array([[ np.sin(lat_r)*np.cos(lon_r), np.sin(lat_r)*np.sin(lon_r), -np.cos(lat_r)], [-np.sin(lon_r), np.cos(lon_r), 0], [np.cos(lat_r)*np.cos(lon_r), np.cos(lat_r)*np.sin(lon_r),np.sin(lat_r)]])

    return Qxx_mat



#==========================================================
def main():
    '''
    The various input files are read in, so that their data can be used to calculate the azimuth and zenith angles of the spacecraft and sun with respect to a topcentric NEZ frame centered on the landmark during the exact moment a picture is taken of said landmark.
    A text file is then created listing the angles, picture resolution, and picture UTC time.
    '''
    
    '''
    Reading in TXT Files
    '''

    fid1 = open('LAT.txt')
    fid2 = open('LON.txt')
    fid3 = open('NUMBERPIC.txt')
    fid4 = open('PICTIMES.txt')
    fid5 = open('lmrkname.txt')
    fid6 = open('RESOLUTION.txt')
    fid7 = open('SCOBJ1.txt')
    fid8 = open('SCOBJ2.txt')
    fid9 = open('SCOBJ3.txt')
    fid10 = open('SZ1.txt')
    fid11 = open('SZ2.txt')
    fid12 = open('SZ3.txt')
    fid13 = open('VLM1.txt')
    fid14 = open('VLM2.txt')
    fid15 = open('VLM3.txt')
    
    '''
    Getting latitude and longitude of landmark
    '''
    
    lat = float(fid1.readline().rstrip())
    
    lon = 360 - float(fid2.readline().rstrip())
    
    '''
    Getting object center to landmark vector components and then vector
    '''
    
    VLM1 = fid13.readline().rstrip()
    
    VLM1 = float(VLM1.replace('D', 'E'))
    
    VLM2 = fid14.readline().rstrip()
    
    VLM2 = float(VLM2.replace('D', 'E'))
    
    VLM3 = fid15.readline().rstrip()

    VLM3 = float(VLM3.replace('D', 'E'))
    
    lmrk_vec = BEN2LMRK(VLM1, VLM2, VLM3)
    
    '''
    Getting number of pictures and landmark name
    '''
    
    number_pics = int(fid3.readline().rstrip())
    
    lmrk_name = fid5.readline().rstrip()
    
    '''
    Formting outputs & creating text file
    '''
    
    file = open(lmrk_name+"_viewing.txt", "w")
    file.write( "\n")
    file.write( lmrk_name)
    file.write( "\n")
    file.write( "lat = %f,   Elon = %f\n" % (lat, lon))
    file.write( "# of pictures taken = %f\n" % (number_pics))
    file.write("\n")
    file.write( "|             UTC            |    res    |  sun_zen   |  sun_azi   |  sc_zen    |   sc_azi   |\n")
    file.write( "|--------------------------------------------------------------------------------------------|\n")
    
    '''
    for loop
    '''
    
    for j in range(0, number_pics):
       
        '''
        Getting the SCOBJ vector components one line at a time
        '''
        
        SCOBJ1 = fid7.readline().rstrip()
        
        SCOBJ1 = float(SCOBJ1.replace('D', 'E'))
        
        SCOBJ2 = fid8.readline().rstrip()
        
        SCOBJ2 = float(SCOBJ2.replace('D', 'E'))
        
        SCOBJ3 = fid9.readline().rstrip()
        
        SCOBJ3 = float(SCOBJ3.replace('D', 'E'))
        
        '''
        Getting the SZ vector components one line at a time
        '''
        
        SZ1 = fid10.readline().rstrip()
        
        SZ1 = float(SZ1.replace('D', 'E'))
        
        SZ2 = fid11.readline().rstrip()
        
        SZ2 = float(SZ2.replace('D', 'E'))
        
        SZ3 = fid12.readline().rstrip()
        
        SZ3 = float(SZ3.replace('D', 'E'))
        
        '''
        Getting picture resolution one line at a time
        '''
        
        res = float(fid6.readline().rstrip())
        
        '''
        Getting UTC time of each picture one line at a time
        '''
        
        time = fid4.readline().rstrip()
       
        '''
        SC Calculations
        
        lmrk2sc_vec: landmark to sc vector in body fixed frame
        
        n_sc: landmark to sc vector in topographical SEZ frame
        
        elvation_sc: elevation angle of n_sc
        
        zenith_sc: zenith angle of n_sc
        
        azimuth_sc: azimuth angle of n_sc, but manipulated so it is in NEZ frame opposed to SEZ
        '''
    
        lmrk2sc_vec = np.subtract(SCPOS(SCOBJ1, SCOBJ2, SCOBJ3),lmrk_vec)
    
        n_sc = np.dot(BF2SEZ_tm(lon,lat),lmrk2sc_vec)
    
        elevation_sc = np.degrees(np.arcsin(np.true_divide(n_sc[2],np.linalg.norm(n_sc))))
    
        zenith_sc = 90-elevation_sc
    
        azimuth_sc = np.degrees(np.arctan2(n_sc[1],-n_sc[0]))

        if azimuth_sc < 0:
            azimuth_sc = 360+azimuth_sc

        else:
            azimuth_sc = azimuth_sc

        '''
        Sun Calculations
        
        lmrk2sun_vec: landmark to sun vector in body fixed frame
        
        n_sun: landmark to sun vector in topographical SEZ frame
        
        elvation_sun: elevation angle of n_sun
        
        zenith_sun: zenith angle of n_sun
        
        azimuth_sun: azimuth angle of n_sun, but manipulated so it is in NEZ frame opposed to SEZ
        '''
    
        lmrk2sun_vec = np.subtract(SUNPOS(SZ1, SZ2, SZ3),lmrk_vec)
    
        n_sun = np.dot(BF2SEZ_tm(lon,lat),lmrk2sun_vec)
    
        elevation_sun = np.degrees(np.arcsin(np.true_divide(n_sun[2],np.linalg.norm(n_sun))))
    
        zenith_sun = 90-elevation_sun
    
        azimuth_sun = np.degrees(np.arctan2(n_sun[1],-n_sun[0]))

        if azimuth_sun < 0:
            azimuth_sun = 360+azimuth_sun

        else:
            azimuth_sun = azimuth_sun
        
        '''
        Continued formatting of text file
        '''
        
        file.write("|  ")
        file.write(time)
        file.write("  ")
        file.write( "|  %07.3f  |  %+08.3f  |  %08.3f  |  %+08.3f  |  %08.3f  \n" % (res, zenith_sun, azimuth_sun, zenith_sc, azimuth_sc))

    file.close()




    with open(lmrk_name+"_viewing.txt") as ifh:
        arr = np.loadtxt(ifh, usecols = (1,2,3,4,5), dtype = float, delimiter = " | ", skiprows = 7)

    theta = np.linspace(-np.pi, np.pi, 100)
    azi_sun_1 = arr[:,2]
    zen_sun_1 = arr[:,1]
    azi_sc_1 = arr[:,4]
    zen_sc_1 = arr[:,3]
    res = arr[:,0]

    '''
    Sun plot
    '''

    plt.figure(1)

    ax1 = plt.subplot(111, polar = True)

    ax1.set_theta_zero_location("N")

    ax1.set_theta_direction(-1)

    plt.grid(True)

    ax1.set_rgrids([15,30,45,60,75,90], angle = 60, fontsize = 10)
    
    ax1.set_rlim(0, 90)

    ax1.set_thetagrids([0, 45, 90, 135, 180, 225, 270, 315], frac = 1.08, fontsize = 10)

    for k in range(0, number_pics):
        if res[k] >=1:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'or')
        elif 1 > res[k] and res[k] >= .5:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'og')
        elif .5 > res[k] and res[k] >= .25:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'ob')
        elif .25 > res[k] and res[k] >= .1:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'oy')
        elif .1 > res[k] and res[k] >= .05:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'om')
        else:
            ax1.plot(np.radians(azi_sun_1[k]), zen_sun_1[k], 'oc')

    mot1 = mpatches.Patch( color = 'r', label = 'Res $\geq$ 50 cm')
    
    mot2 = mpatches.Patch( color = 'g', label = '100 cm > Res $\geq$ 50 cm')
    
    mot3 = mpatches.Patch( color = 'b', label = '50 cm > Res $\geq$ 25 cm')
    
    mot4 = mpatches.Patch( color = 'y', label = '25 cm > Res $\geq$ 10 cm')
    
    mot5 = mpatches.Patch( color = 'm', label = '10 cm > Res $\geq$ 5 cm')
    
    mot6 = mpatches.Patch( color = 'c', label = 'Res < 5 cm')
    
    plt.legend( handles = [mot1, mot2, mot3, mot4, mot5, mot6], fontsize = 8, loc = 2, bbox_to_anchor = (.93, 1.1))

    figure_title1 = lmrk_name+' Sun Azimuth vs. Zenith'

    plt.text(.5, 1.08,figure_title1,
            horizontalalignment = 'center',
             fontsize = 15,
             transform = ax1.transAxes)

    plt.savefig( lmrk_name+'_sun_plot.png')

    plt.clf()

    '''
    SC plot
    '''

    plt.figure(2)

    ax2 = plt.subplot(111, polar = True)

    ax2.set_theta_zero_location("N")
    
    ax2.set_theta_direction(-1)

    plt.grid(True)
    
    ax2.set_rgrids([15,30,45,60,75,90], angle = 60, fontsize = 10)
    
    ax2.set_rlim(0, 90)
    
    ax2.set_thetagrids([0, 45, 90, 135, 180, 225, 270, 315], frac = 1.08, fontsize = 10)

    for k in range(0, number_pics):
        if res[k] >=1:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'or')
        elif 1 > res[k] and res[k] >= .5:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'og')
        elif .5 > res[k] and res[k] >= .25:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'ob')
        elif .25 > res[k] and res[k] >= .1:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'oy')
        elif .1 > res[k] and res[k] >= .05:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'om')
        else:
            ax2.plot(np.radians(azi_sc_1[k]), zen_sc_1[k], 'oc')

    dot1 = mpatches.Patch( color = 'r', label = 'Res $\geq$ 50 cm')

    dot2 = mpatches.Patch( color = 'g', label = '100 cm > Res $\geq$ 50 cm')

    dot3 = mpatches.Patch( color = 'b', label = '50 cm > Res $\geq$ 25 cm')

    dot4 = mpatches.Patch( color = 'y', label = '25 cm > Res $\geq$ 10 cm')

    dot5 = mpatches.Patch( color = 'm', label = '10 cm > Res $\geq$ 5 cm')

    dot6 = mpatches.Patch( color = 'c', label = 'Res < 5 cm')

    plt.legend( handles = [dot1, dot2, dot3, dot4, dot5, dot6], fontsize = 8, loc = 2, bbox_to_anchor = (.93, 1.1))

    figure_title2 = lmrk_name+' SC Azimuth vs. Zenith'
    
    plt.text(.5, 1.08,figure_title2,
            horizontalalignment = 'center',
            fontsize = 15,
            transform = ax2.transAxes)

    plt.savefig(lmrk_name+'_sc_plot.png')

    plt.clf()

    #print(n_sc)
    #print(lmrk2sc_vec)
    #print(elevation_sc)
    #print(elevation_sun)
    #print(BF2SEZ_tm(lon,lat))

if __name__ == '__main__':
    main()