Source code for edges.analysis.aux_data

"""Module for dealing with auxiliary data for EDGES observations."""

import logging
import time
from pathlib import Path

import numpy as np
from astropy.table import QTable
from astropy.time import Time
from pygsdata import GSData, gsregister

from .. import types as tp
from ..config import config
from ..io.auxiliary import read_thermlog_file, read_weather_file

logger = logging.getLogger(__name__)


[docs] class WeatherError(ValueError): """Error for weather data issues."""
def _interpolate_times(thing: QTable, times: Time) -> QTable: t0 = times[0] seconds = (times - t0).to_value("s") interpolated = {} thing_seconds = (thing["time"] - t0).to_value("s") for col in thing.colnames: if col == "time": continue interpolated[col] = np.interp(seconds, thing_seconds, thing[col]) return QTable(interpolated)
[docs] @gsregister("supplement") def add_weather_data(data: GSData, weather_file: tp.PathLike | None = None) -> GSData: """Add weather data to a :class`GSData` object. This adds data specifically from a file maintained by EDGES. Parameters ---------- data Object into which to add the weather data. weather_file Path to a weather file from which to read the weather data. Must be formatted appropriately. By default, will choose an appropriate file from the configured `raw_field_data` directory. If provided, will search in the current directory and the `raw_field_data` directory for the given file (if not an absolute path). """ times = data.times[..., data.loads.index("ant")] start = min(times) end = max(times) pth = config.raw_field_data if (pth is None and weather_file is None) or not Path(weather_file).exists(): raise ValueError( "weather file not given, but not configuration set to specify where " "raw data is" ) if weather_file is not None: if not weather_file.exists() and not weather_file.is_absolute(): weather_file = pth / weather_file elif (start.year, start.day) <= (2017, 329): weather_file = pth / "weather_upto_20171125.txt" else: weather_file = pth / "weather2.txt" # Get all aux data covering our times, up to the next minute (so we have some # overlap). weather = read_weather_file( weather_file, start=start, end=end, ) if len(weather) == 0: raise WeatherError( f"Weather file '{weather_file}' has no dates between " f"{start.strftime('%Y/%m/%d')} " f"and {end.strftime('%Y/%m/%d')}." ) logger.info("Setting up arrays...") t = time.time() # Interpolate weather interpolated = _interpolate_times(weather, times) logger.info(f"Took {time.time() - t} sec to interpolate weather data.") return data.update( auxiliary_measurements=data.auxiliary_measurements | interpolated )
[docs] @gsregister("supplement") def add_thermlog_data( data: GSData, band: str | None = None, thermlog_file: tp.PathLike | None = None ) -> GSData: """Add thermlog data to a :class`GSData` object. This adds data specifically from a file maintained by EDGES. Parameters ---------- data Object into which to add the weather data. band The instrument taking the data. Only provide to automatically find the correct data. thermlog_file Path to a weather file from which to read the weather data. Must be formatted appropriately. By default, will choose an appropriate file from the configured `raw_field_data` directory. If provided, will search in the current directory and the `raw_field_data` directory for the given file (if not an absolute path). """ times = data.times[..., data.loads.index("ant")] start = min(times) end = max(times) pth = config.raw_field_data if (pth is None and thermlog_file is None) or not Path(thermlog_file).exists(): raise ValueError( "thermlog file not given, but not configuration set to specify where " "raw data is" ) if thermlog_file is None: thermlog_file = pth / f"thermlog_{band}.txt" elif not thermlog_file.exists() and not thermlog_file.is_absolute(): thermlog_file = pth / thermlog_file # Get all aux data covering our times, up to the next minute (so we have some # overlap). thermlog = read_thermlog_file( thermlog_file, start=start, end=end, ) if len(thermlog) == 0: raise WeatherError( f"Thermlog file '{thermlog_file}' has no dates between " f"{start.strftime('%Y/%m/%d')} " f"and {end.strftime('%Y/%m/%d')}." ) logger.info("Setting up arrays...") t = time.time() interpolated = _interpolate_times(thermlog, times) logger.info(f"Took {time.time() - t} sec to interpolate thermlog data.") return data.update( auxiliary_measurements=data.auxiliary_measurements | interpolated )