# make_beam_steering_table.py for python 3.8
# Dave Typinski, 29 July 2021
#
# Purpose:
#   Create a tex-based table of dates upon which a phased array should be
#   steered due to changes in Jupiter's transit elevation.
#
# Inputs:
#   station_name -> string, the name of the target station
#   station_antenna -> string, the target station's antenna type
#   station_lat -> float, the target station's latitude
#   station_south_offset -> float, the target station's antenna's southward
#                           offset from zenith with no beam steering.
#   ns_inc -> int -> beam steering increment for target station
#   max_za -> int -> max zenith angle to steer for target station
#
# Output:
#   Text file listing:
#       Dates when beam steering should be changed and
#       Dates when Jupiter's transit elevation reaches a local min or max
#   NOTE: Beam steering angles > max_za are denoted with a * suffix

import pandas as pd
from decimal import Decimal, ROUND_HALF_UP

# Start of user-definable constants ---------------------------------------

station_name = 'AJ4CO'
station_antenna = '8-Element TFD Array'
station_lat = 29.8369
station_south_offset = 0.0

ns_inc = 5
max_za = 45

# End of user-definable constants------------------------------------------

log_file_name = 'AJ4CO Jupiter Transit Log.xls'
log_file_lat = 29.8369

out_file_title1 = station_name + ' ' + station_antenna + ' Beam Steering'
out_file_title2 = (f'{station_lat:.1f}' + '° N Latitude, '
                  + f'{station_south_offset:.0f}' + '° S Array Offset ')
out_file_title3 = (f'{ns_inc:.0f}' + '° Steering Increment, '
                  + f'{max_za:.0f}' + '° Max Steering')

out_file_name = (out_file_title1 + '.txt').replace(' ','_')

lat_offset = station_lat - log_file_lat

# read the Excel events log file
df = pd.read_excel(log_file_name, sheet_name='AJ4CO Transit Log',
                   skiprows=9)
print('Imported',log_file_name)
print('Log file has',df.shape[0],'rows and',df.shape[1],'columns')

# filter log file for only those records with emission events recorded
df_valid = df.query('transit_JD>0').iloc[:,[3,18]]
print('Found',df_valid.shape[0],'valid records with emission JDUTs.')

#create list of 2 column names
column_names = ['Transit UTC',
                'Jupiter Tr EL /Dir',
                'Beam Steering ZA']

# write column names to the output file
with open(out_file_name, "w+") as fp:
    fp.write(out_file_title1 + '\n')
    fp.write('=' * len(out_file_title1) + '\n')
    fp.write(out_file_title2 + '\n')
    fp.write(out_file_title3 + '\n\n')
    fp.write(column_names[0]
             + '     '
             + column_names[1]
             + '    '
             + column_names[2]
             + '\n')
    fp.write('========================================================\n')
    fp.write('\n')

    bza = 0 # set initial beam steering zenith angle

    # Cycle over all valid transit log records
    for i in range(len(df_valid)):
        
        # Jupiter transit zenith angle
        jza = 90 - df_valid.iloc[i,1] + lat_offset - station_south_offset
        
        # calculate required beam steering in terms of zenith angle
        bzatest = (ns_inc *
                   Decimal(jza/ns_inc).quantize(0, ROUND_HALF_UP))
        
        # no new steering needed
        if bzatest == bza: 
            if i > 0 and i < len(df_valid)-1:
                # check for local maxima
                if (df_valid.iloc[i,1] > df_valid.iloc[i+1,1]
                    and df_valid.iloc[i,1] > df_valid.iloc[i-1,1]):
                    fp.write(df_valid.iloc[i,0][:11])
                    fp.write('        ')
                    ang = df_valid.iloc[i,1] - lat_offset
                    fp.write(f'{ang:.1f}'.zfill(2) + '° -Max-')
                    fp.write('\n\n')
                # check for local minima
                elif (df_valid.iloc[i,1] < df_valid.iloc[i+1,1]
                      and df_valid.iloc[i,1] < df_valid.iloc[i-1,1]):
                    fp.write(df_valid.iloc[i,0][:11])
                    fp.write('        ')
                    ang = df_valid.iloc[i,1] - lat_offset
                    fp.write(f'{ang:.1f}'.zfill(2) + '° -Min-')
                    fp.write('\n\n')
                # not local max or local min; continue with loop
                else:
                    continue
            # not within checkable bounds of list; i.e., can't check for
            # local min or local max at first and last entry of transit log 
            # file, so just ignore and continue with loop
            else:
                continue
        # beam steering to be changed this date
        else:
            bza = bzatest 
            # determine the day-to-day motion of Jupiter's transit EL
            if i < len(df_valid)-1:
                if df_valid.iloc[i,1] > df_valid.iloc[i+1,1]:
                    dir = 'down'
                else:
                    dir = 'up  '
            # special case for last entry of transit log
            else:
                if df_valid.iloc[i,1] > df_valid.iloc[i-1,1]:
                    dir = 'up  '
                else:
                    dir = 'down'
            fp.write(df_valid.iloc[i,0][:11])
            fp.write('        ')
            ang = df_valid.iloc[i,1] - lat_offset
            fp.write(f'{ang:.1f}'.zfill(2) + '° /' + dir)
            fp.write('       ')
            # southward steering ZA is positive,
            # northward steering ZA is negative
            if bza < 0:
                bzatext = '       ' + str(bza * -1).zfill(2) + 'N'
            elif bza > 0:
                bzatext = '       ' + str(bza).zfill(2) + 'S'
            else:
                bzatext = 'Zero (array zenith)'
            fp.write(bzatext)
            if bza > max_za:
                fp.write('*')
            fp.write('\n\n')

print('Done.')
