Browse Source

Minor issues

Benito Marcote 4 years ago
  1. 220


@ -1,220 +0,0 @@
Python port of Bob Campbell's IDL script to make nominal tsys tables.
It takes the nominal SEFD values from the sefd_values.txt table and generates an ANTAB file using
these values. Gains will be set to 1/SEFD, and all Tsys to 1.0.
Note that it will overwrite any existing ANTAB file in the current path.
Version: 4.0
Date: June 2018
Author: Benito Marcote ( & Jay Blanchard (
version 4.0 changes
- Major code changes for a better exception handling
version 3.0 changes
- new argument to set the freq. interval (-fr / --freqrange)
version 2.0 changes
- interactive or argument-based
- documentation!!
- Takes SEFD values from status table of EVN
import sys
import argparse
import datetime as dt
from math import floor
from collections import defaultdict
help_str = """Writes a nominal SEFD ANTAB file. Gain will be set to 1/SEFD, and all Tsys to 1.0.
It will overwrite any previous antab file in the current path. uses the SEFD information from sefd_values.txt to compute the nominal values.
Creates (or overwrites) a file called <experiment><antenna>.antabfs, where <experiment> and
<antenna> are the input from the user.
parser = argparse.ArgumentParser(description='help_str')
parser.add_argument('antenna', type=str, default=None, help='Antenna name (two-letters syntax, except for Jb1 Jb2 Ro7 Ro3)')
parser.add_argument('experiment', type=str, default=None, help='Experiment name')
parser.add_argument('start', type=str, default=None, help='Start time (DOY/HH:MM, YYYY/DOY/HH:MM or YYYY/MM/DD/HH:MM)')
parser.add_argument('-d', '--duration', type=float, default=24, help='Duration of the experiment (in hours). Default: 24 h')
parser.add_argument('-b', '--band', type=str, default=None, help='Observed band (in cm). Optional only if SEFD provided')
parser.add_argument('-fr', '--freqrange', type=str, default='100,100000', help='Frequency range where the ANTAB is applicable (lower and upper limit, in MHz). Default 100,100000 (please, do not use spaces between the numbers).')
parser.add_argument('-s', '--sefd', type=float, default=None, help='SEFD to be used (optional). Default values are loaded.')
parser.add_argument('-i', '--interval', type=float, default=0.25, help='Interval between Tsys measurements (in min). Default: 0.5')
parser.add_argument('-sb', '--subbands', type=int, default=8, help='Number of subbands in the experiment. Default: 8 = L1|R1 L2|R2 ... L8|R8')
args = parser.parse_args()
i_already_warn_about_seconds = False
# def read_sefd_table(tablename='sefd_values.txt'):#'/jop83_0/pipe/in/marcote/scripts/sefd_values.txt'):
def read_sefd_table(tablename='/jop83_0/pipe/in/marcote/scripts/sefd_values.txt'):
sefd_table = open(tablename, 'r')
titles = sefd_table.readline().strip().split('|')
titles = [t.strip() for t in titles]
sefd_dict = defaultdict(dict)
for an_ant in sefd_table.readlines():
values = [ t.strip() for t in an_ant.strip().split('|')]
for i in range(1, len(values)):
if values[i] != '':
sefd_dict[values[0].lower()][titles[i]] = float(values[i])
return sefd_dict
def read_sefd_values(table, antenna, band):
return table[antenna][band]
except KeyError:
if antenna not in table:
print('ERROR: {} is not available.\n'.format(antenna))
print('The available antennas are: ', ' '.join(table.keys()))
print('ERROR: antenna {} does not have SEFD information for {}-cm observations'.format(antenna, band))
def index_header():
indexes = list()
for i in range(1, args.subbands+1):
return ','.join(indexes)
def get_header(antenna, gain, freqrange):
"""Returns the apropiate header for the given antenna using a given gain value.
antenna : str
The antenna name (two letters syntax)
gain : float
The gain (in 1/Jy) for this antenna
generic_header = '''!
! Nominal calibration data for {ant} by
! version 2.0, 2016 August 3, BM & JB
GAIN {ant} ELEV DPFU={gain},{gain} POLY=1.0 FREQ={freqrange}
TSYS {ant} FT=1.0 TIMEOFF=0
INDEX = {indexes}
return generic_header.format(ant=antenna[:2].upper(), gain=gain, indexes=index_header(),
freqrange=','.join([str(i) for i in freqrange]))
def hm2hhmmss(hhmm):
"""Takes a time in str format HH:MM.MM and returns int(hh), int(mm), float(ss)"""
hour, minute = hhmm.split(':')
except ValueError:
if not i_already_warn_about_seconds:
print('WARNING: only HH:MM are read. Seconds or other smaller numbers are going to be ignored.')
i_already_warn_about_seconds = True
hour, minute, *others = hhmm.split(':')
minute = float(minute)
second = int((minute-floor(minute))*60)
return int(hour), int(floor(minute)), second
def date2datetime(date):
"""Convert the given date to DOY, HH, MM.
date : str
if date.count('/') == 1:
# Uses a fake year
doy, hhmm = date.split('/')
return dt.datetime(1969, 1, 1, *hm2hhmmss(hhmm)) + dt.timedelta(int(doy)-1)
elif date.count('/') == 2:
year, doy, hhmm = date.split('/')
return dt.datetime(int(year), 1, 1, *hm2hhmmss(hhmm)) + dt.timedelta(int(doy)-1)
elif date.count('/') == 3:
year, month, day, hhmm = date.split('/')
return dt.datetime(int(year), int(month), int(day), *hm2hhmmss(hhmm))
print('Error: date must have the following format: DOY/HH:MM, YYYY/DOY/HH:MM or YYYY/MM/DD:HH:MM')
raise SyntaxError
def date2string(datetime):
"""Return a string with the date in the correct ANTAB format
return '{} {:02d}:{:05.2f}'.format(datetime.strftime('%j'), datetime.hour, datetime.minute+datetime.second/60.)
#currently asks for inputs, might change this in future to read from vex...
if args.experiment == None:
args.experiment = raw_input("Input experiment name: ")
if args.antenna == None:
args.antenna = raw_input("Input antenna name (two-letter syntax (except Jb1 Jb2 Ro7 Ro3): ")
if == None and args.sefd == None:
output = raw_input("Input frequency band (cm) or SEFD value (Jy). Write 'band VALUE' or 'sefd VALUE'").split(' ')
if output[0].lower() == 'band': = output[1]
elif output[0].lower() == 'sefd':
args.sefd = output[1]
print('Wrong format. It must be either: "band VALUE" or "sefd VALUE"')
raise ValueError
if args.start == None:
input_starttime = raw_input("Enter start day of the year, hour and minute (comma separated): ").split(',')
args.start = '{} {}:{}'.format(*input_starttime)
dur = raw_input("Enter duration (hours; enter to default): ")
if dur != '':
args.duration = float(dur)
# Read and interpretate the freqrange.
if args.freqrange.count(',') != 1:
print('The frequency range (--freqrange) must contain two values (comma-separated): the lower and upper frequency limit in MHz (please, do not use spaces between the numbers).')
args.freqrange = [int(i) for i in args.freqrange.split(',')]
if not (args.freqrange[0] < 30*1000/float( < args.freqrange[1]):
print('The provided frequency range must contain the frequency band, and this is not the case.')
print('Introduced band: {} GHz'.format(30/float(
print('Introduced frequency range: {}-{} GHz'.format(args.freqrange[0]/1e3, args.freqrange[1]/1e3))
sefd_info = read_sefd_table()
start_time = date2datetime(args.start)
end_time = start_time + dt.timedelta(args.duration/24.)
a_time = date2datetime(args.start)
# Creating the ANTAB file
antab_file = open('{}{}.antabfs'.format(args.experiment.lower(), args.antenna.lower()[:2]), 'wt')
antab_file.write(get_header(args.antenna.lower(), 1./read_sefd_values(sefd_info, args.antenna.lower(),,
while a_time < end_time:
antab_file.write('{}{}\n'.format(date2string(a_time), ' 1.0'*args.subbands))
a_time = a_time + dt.timedelta(args.interval/(60*24.))
antab_file.write('/\n') # antab expects trailing /
print('File {}{}.antabfs created successfully.'.format(args.experiment.lower(), args.antenna.lower()[:2]))