"""Flag file utilities for antenna and visibility flagging.
Provides functions for reading and writing flag data, looking up
bad antennas from the flag database, and visualizing flag statistics.
"""
import datetime
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
import subprocess
import ast
import textwrap
[docs]
FLAG_TABLE = '/opt/devel/yuping/ant_flags.csv'
# Load flag table if it exists, otherwise create empty DataFrame
if os.path.exists(FLAG_TABLE):
[docs]
df = pd.read_csv(FLAG_TABLE, parse_dates=['date'])
else:
df = pd.DataFrame(columns=['date', 'ant', 'source'])
[docs]
def get_bad_ants(date: datetime.date, sources=['AI-VAR', 'AI-LO']):
"""Return a list of bad antennas for a given date and kinds of flags.
Args:
date: The date
sources: Sources of flags. Default is ['AI-VAR', 'AI-LO'].
Returns:
A list of bad antenna corr numbers.
"""
# Sigh, hardcoded gaps.
if date == datetime.date(2024, 1, 23):
date = datetime.date(2024, 1, 22)
elif datetime.date(2024, 5, 7) < date <= datetime.date(2024, 5, 11):
date = datetime.date(2024, 5, 7)
elif datetime.date(2024, 5, 11) < date < datetime.date(2024, 5, 15):
date = datetime.date(2024, 5, 15)
elif date > datetime.date(2024, 5, 20): # last available date
date = datetime.date(2024, 5, 20)
res = df[df['source'].isin(sources) & (df['date'] == str(date))]['corr_num'].sort_values().unique().tolist()
if not res or len(res) == 0:
raise ValueError(f"No bad antennas found for {date}.")
return res
# Test the function on the provided file
# unpacked_flags = unpack_flag_metadata(input_file, original_shape)
# plot_flag_metadata_all_polarizations_subplot(unpacked_flags, output_dir=None) # Set output_dir to save the plot instead of displaying it
[docs]
def get_bad_antenna_names(date_time_str):
"""
Get a list of bad antenna names (e.g., 'LWA-005B') using the 'development' conda environment.
Args:
date_time_str (str): Date and time string in ISO format, e.g. '2025-01-28 19:20:04'
Returns:
list: List of bad antenna names
"""
code = textwrap.dedent("""
from mnc import anthealth
from astropy.time import Time
dt = '{}'
b = anthealth.get_badants('selfcorr', time=Time(dt, format='iso').mjd)
print(b[1])
""".format(date_time_str))
result = subprocess.run(
["conda", "run", "-n", "development", "python", "-c", code],
capture_output=True, text=True
)
if result.returncode != 0:
raise RuntimeError("Error running command:\n{}".format(result.stderr))
lines = result.stdout.strip().splitlines()
list_line = next((line for line in reversed(lines) if line.startswith("['LWA-")), None)
if not list_line:
raise ValueError("Could not find a valid list of bad antennas in output:\n{}".format(result.stdout))
try:
return ast.literal_eval(list_line)
except Exception as e:
raise ValueError("Failed to parse antenna list:\n{}".format(list_line)) from e
[docs]
def get_bad_correlator_numbers(date_time_str):
code = textwrap.dedent("""
from mnc import anthealth
from astropy.time import Time
import lwa_antpos.mapping as mapping
dt = '{}'
b = anthealth.get_badants('selfcorr', time=Time(dt, format='iso').mjd)
badnames = b[1]
correlators = [
mapping.antname_to_correlator(name.rstrip('A').rstrip('B'))
for name in badnames
]
print(sorted(set(correlators)))
""".format(date_time_str))
result = subprocess.run(
["conda", "run", "-n", "development", "python", "-c", code],
capture_output=True, text=True
)
if result.returncode != 0:
raise RuntimeError("Error running command:\n{}".format(result.stderr))
lines = result.stdout.strip().splitlines()
list_line = next((line for line in reversed(lines) if line.startswith("[")), None)
if not list_line:
raise ValueError("Could not find a valid list of correlators in output:\n{}".format(result.stdout))
try:
return ast.literal_eval(list_line)
except Exception as e:
raise ValueError("Failed to parse correlator list:\n{}".format(list_line)) from e