Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
holography_observation.py 7.13 KiB
import re
import os
import astropy.time as astrotime
from datetime import datetime
from .holography_measurementset import HolographyMeasurementSet

class HolographyObservation():
    def __init__(self, path, sas_id, ms_for_a_given_beamlet_number, start_mjd_in_seconds,
                 end_mjd_in_seconds, sub_band, frequency, source_name):
        """

        :param path:
        :type path: str
        :param sas_id:
        :type sas_id: int
        :param ms_for_a_given_beamlet_number:
        :type ms_for_a_given_beamlet_number: dict[int, HolographyMeasurementSet]
        :param start_mjd_in_seconds:
        :type start_mjd_in_seconds: float
        :param end_mjd_in_seconds:
        :type end_mjd_in_seconds: float
        :param sub_band:
        :type sub_band: int
        :param frequency:
        :type frequency: float
        :param source_name:
        :type source_name: str
        """
        self.path = path
        self.sas_id = sas_id
        self.ms_for_a_given_beamlet_number = ms_for_a_given_beamlet_number
        self.start_datetime = HolographyObservation.__mjd_to_datetime(start_mjd_in_seconds)
        self.end_datetime = HolographyObservation.__mjd_to_datetime(end_mjd_in_seconds)
        self.start_mjd = start_mjd_in_seconds
        self.end_mjd = end_mjd_in_seconds
        self.sub_band = sub_band
        self.frequency = frequency
        self.source_name = source_name

    @staticmethod
    def __mjd_to_datetime(mjd_time_seconds):
        """
        Convert the modified julian date in seconds in a datetime object
        :param mjd_time_seconds: modified julian data in seconds
        :return: the date time of the given julian date
        :rtype: datetime
        """
        hour_in_seconds = 60 * 60
        day_in_seconds = hour_in_seconds * 24
        return astrotime.Time(mjd_time_seconds / day_in_seconds, format='mjd',
                              scale='utc').to_datetime()

    @staticmethod
    def __compute_time_range_from_ms_list(ms_list):
        observation_start, observation_end = ms_list[0].get_start_end_observation()
        for ms in ms_list:
            ms_start_time, ms_end_time = ms.get_start_end_observation()
            if observation_start > ms_start_time:
                observation_start = ms_start_time
            if observation_end < ms_end_time:
                observation_end = ms_end_time
        return observation_start, observation_end

    @staticmethod
    def extract_unique_source_names_from_ms_list(ms_list):
        """
        Returns a set of unique source names given a list of measurement sets
        :param ms_list: a list of measurement set where to extract the reference frequencies
        :type ms_list: list[HolographyMeasurementSet]
        :return: a set of frequencies
        :rtype: set[str]
        """
        return {ms.get_source_name() for ms in ms_list}

    @staticmethod
    def extract_unique_subband_from_ms_list(ms_list):
        """
        Returns a set of unique rcu modes given a list of measurement sets
        :param ms_list: a list of measurement set where to extract the reference frequencies
        :type ms_list: list[HolographyMeasurementSet]
        :return: a set of rcu modes
        :rtype: set[int]
        """
        return {ms.get_subband() for ms in ms_list}

    @staticmethod
    def list_observations_in_path(path):
        """
        List all the observations in the given path and return a list of HolographyObservation

        :param path: path to the directory where the holography observation is stored\
        :type path: str
        :return: a list of HolographyObservation
        :rtype: list[HolographyObservation]
        """
        ms_dir_name_pattern = 'L(?P<sas_id>\d{6})'
        ms_dirs_path_pattern = '^' + os.path.join(path, ms_dir_name_pattern, 'uv$')
        observations_list = []
        for root, dirnames, filenames in os.walk(path):
            match = re.match(ms_dirs_path_pattern, root)
            if match:
                sas_id = match.group('sas_id')

                ms_indexed_per_beamlet_number = HolographyObservation. \
                    create_ms_dict_from_ms_name_list_and_path(dirnames, root)


                start_mjd_in_seconds, end_mjd_in_seconds = HolographyObservation.\
                    __compute_time_range_from_ms_list(
                    ms_indexed_per_beamlet_number.values())

                unique_frequencies = HolographyObservation. \
                    extract_unique_reference_frequencies_from_ms_list(
                    ms_indexed_per_beamlet_number.values())

                if len(unique_frequencies) > 1:
                    raise ValueError(
                        'Multiple reference frequencies per observation are not supported')
                else:
                    frequency = unique_frequencies.pop()

                unique_source_names = HolographyObservation.\
                    extract_unique_source_names_from_ms_list(ms_indexed_per_beamlet_number.values())

                if len(unique_source_names) > 1:
                    raise ValueError(
                        'Multiple source target per observation are not supported'
                    )
                else:
                    source_name = unique_source_names.pop()

                unique_subband = HolographyObservation.\
                    extract_unique_subband_from_ms_list(ms_indexed_per_beamlet_number.values())

                if len(unique_subband) > 1:
                    raise ValueError(
                        'Multiple subband per observation are not supported'
                    )
                else:
                    sub_band = unique_subband.pop()

                observations_list.append(
                    HolographyObservation(path, sas_id, ms_indexed_per_beamlet_number,
                                          start_mjd_in_seconds, end_mjd_in_seconds, sub_band,
                                          frequency,
                                          source_name))
        return observations_list

    @staticmethod
    def extract_unique_reference_frequencies_from_ms_list(ms_list):
        """
        Returns a set of reference frequencies given a list of measurement setss
        :param ms_list: a list of measurement set where to extract the reference frequencies
        :type ms_list: list[HolographyMeasurementSet]
        :return: returns a set of frequencies
        :rtype: set[float]
        """
        return {ms.get_frequency() for ms in ms_list}

    @staticmethod
    def create_ms_dict_from_ms_name_list_and_path(list_of_ms_names, path):
        """
        Creates a dict measurement sets indexed by beamlet id
        :param list_of_ms_names: a list of the ms to process
        :param path: a path were the ms are stored
        :return: a dict containing the map of the ms indexed by their beamlet number
                            ex. { 0 : ms_beam0 ....}
        :rtype: dict[int, HolographyMeasurementSet]
        """
        filtered_list_of_ms_names = HolographyMeasurementSet.filter_valid_ms_names(list_of_ms_names)
        ms_list = [HolographyMeasurementSet(ms_name, path) for ms_name in filtered_list_of_ms_names]

        beamlet_ms_map = {ms.beamlet:ms for ms in ms_list}  #

        return beamlet_ms_map