From 258d52c3c2a01fa64a3f674129f78b8baeb87ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20J=C3=BCrges?= <jurges@astron.nl> Date: Fri, 5 Oct 2018 15:55:45 +0000 Subject: [PATCH] Task SSB-43: Added code for the central beamlets. --- .../lib/datacontainers/holography_dataset.py | 83 ++++++++++++++++++- .../holography_dataset_definitions.py | 1 + 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/CAL/CalibrationCommon/lib/datacontainers/holography_dataset.py b/CAL/CalibrationCommon/lib/datacontainers/holography_dataset.py index d1a53b791b3..ac3133d845a 100644 --- a/CAL/CalibrationCommon/lib/datacontainers/holography_dataset.py +++ b/CAL/CalibrationCommon/lib/datacontainers/holography_dataset.py @@ -1,5 +1,5 @@ import logging - +import math import h5py from lofar.calibration.common.datacontainers.holography_observation import HolographyObservation @@ -47,6 +47,10 @@ class HolographyDataset(): # list of beamlet numbers self.beamlets = list() + + # The central beam or beamlet for each frequency + self.central_beamlets = dict() + # coordinates of the antenna position in the target self.antenna_field_position = [] # list of reference station names @@ -149,6 +153,75 @@ class HolographyDataset(): return False return equality + def find_central_beamlets(self, source, ra_dec, frequencies, beamlets): + ''' + This function finds the central beamlet of a target station for every + frequency. + @param source: A dict containing right ascension (source["RA"]) and + declination (source["DEC"]) of the source. + @param ra_dec: A dict[frequency][beamlet] that contains the right + ascension (ra_dec[frequency][beamlet][0]) and declination + (ra_dec[frequency][beamlet][1]) for every beamlet. + @param frequencies: A dict that contains the frequencies at which the + holography observation was performed. + @param beamlets: A list of beamlet numbers. + ''' + logger.debug("Finding the central beamlets...") + source_ra = source["RA"] + source_dec = source["DEC"] + # Store each pseudo distance in a dict of dicts: pd[frequency][beamlet] + pseudo_distance = dict() + # Iterate over all frequencies... + for frequency in frequencies: + frequency_string = str(frequency) + pseudo_distance[frequency_string] = dict() + + # and iterate over the beamlets. + for beamlet in beamlets: + beamlet_string = str(beamlet) + (ra, dec, epoch) = ra_dec[frequency_string][beamlet_string] + # calculate a pseudo distance that is an indicator if this + # beamlet is closer to the source than the ones before. + # Note that I am too lazy to calculate the spherical distance. + # But keep in mind that this pseudo distance like its cousin + # the geometrical distance are not really cutting it since RA + # and DEC are coordinates of a spherical coordinate system. + # But here the pseudo distance is good enough. + pseudo_distance[frequency][beamlet] = math.abs(ra - source_ra) + math.abs(dec - source_dec) + + # OK. Done with all the iteration business. Now check if across all + # frequencies the same beamlet is the central one. It is allowed that + # the central beamlets are not always the same but it would be better + # and let the astronomers sleep better if it would always be the same. + # And also check if there is actually only one central beamlet per + # frequency. + central_beamlet = dict() + for (frequency_string, beamlets) in pseudo_distance.items(): + values = beamlets.values() + keys = beamlets.keys() + minimal_distance = min(values) + # If I find a second beamlet that is 'closest' to the source for the + # same frequency then that is a problem. The outset was that there + # is only a single central beamlet and not a bunch of 'em. + if values.count(minimal_distance) == 1: + # All is good. Only one central beamlet. + central_beamlet[frequency_string] = keys[values.index(minimal_distance)] + else: + text = "Found %d beamlets that have the same distance from the source position. Therefore a unique central beamlet does not exist." % (values.count(minimal_distance)) + logger.error(text) + raise ValueError(text) + + # Now check if the central beamlet is the same across all frequencies. + # I do that by creating a set from the central beamlets of all stations. + # If there is only one central beamlet for all frequencies, the size of + # the set will be 1. + central_beamlet_set = set(central_beamlet.values()) + if len(central_beamlet_set) == 1: + logger.debug("All is good, unicorns everywhere, there is only one central beamlet \"%s\" for all frequencies.", self.central_beamlet) + else: + logger.warn("Multiple central beamlets have been identified: ", central_beamlet) + return central_beamlet + def load_from_beam_specification_and_ms(self, station_name, list_of_hbs_ms_tuples): """ Loads the dataset from the specification files and the measurements for the given station @@ -160,6 +233,7 @@ class HolographyDataset(): logger.info("Creating a holography data set for station \"%s\"...", station_name) self.__collect_preliminary_information(station_name, list_of_hbs_ms_tuples) self.__read_data(station_name, list_of_hbs_ms_tuples) + self.central_beamlets = self.find_central_beamlets(self.source_position, self.ra_dec, self.frequencies, self.beamlets) logger.info("Creation of a holography data set for station \"%s\" done.", station_name) def __read_data(self, station_name, list_of_hbs_ms_tuples): @@ -216,6 +290,7 @@ class HolographyDataset(): target_stations = set() reference_stations = set() beamlets = set() + central_beamlet = None virtual_pointing = dict() frequencies = set() sas_ids = set() @@ -339,6 +414,7 @@ class HolographyDataset(): logger.info("Target station position = %s", hds.target_station_position) logger.info("Source name = %s", hds.source_name) logger.info("Source position = %s", hds.source_position) + logger.info("Central beamlet = %s", hds.central_beamlet) logger.info("Start time = %s", hds.start_time) logger.info("End time = %s", hds.end_time) logger.info("Rotation matrix = %s", hds.rotation_matrix) @@ -444,12 +520,13 @@ class HolographyDataset(): result.target_station_name = f.attrs[HDS_TARGET_STATION_NAME] result.target_station_position = list(f.attrs[HDS_TARGET_STATION_POSITION]) result.source_name = f.attrs[HDS_SOURCE_NAME] - result.source_position = tuple(f.attrs[HDS_SOURCE_POSITION].tolist()) + result.source_position = numpy.array(f.attrs[HDS_SOURCE_POSITION]) (result.start_time, result.end_time) = f.attrs[HDS_OBSERVATION_TIME] result.rotation_matrix = f.attrs[HDS_ROTATION_MATRIX] result.antenna_field_position = f.attrs[HDS_ANTENNA_FIELD_POSITION].tolist() result.reference_stations = list(f[HDS_REFERENCE_STATION]) result.frequencies = list(f[HDS_FREQUENCY]) + result.central_beamlets = f.attrs[HDS_CENTRAL_BEAMLETS] result.ra_dec = dict() for frequency in f["RA_DEC"].keys(): @@ -521,6 +598,8 @@ class HolographyDataset(): f.attrs[HDS_ROTATION_MATRIX] = self.rotation_matrix f.attrs[HDS_ANTENNA_FIELD_POSITION] = self.antenna_field_position + f.attrs[HDS_CENTRAL_BEAMLETS] = self.central_beamlets + # Store the list of reference stations and frequencies. We just # want to keep 'em around for quick reference. f[HDS_REFERENCE_STATION] = self.reference_stations diff --git a/CAL/CalibrationCommon/lib/datacontainers/holography_dataset_definitions.py b/CAL/CalibrationCommon/lib/datacontainers/holography_dataset_definitions.py index 837300bdd62..56123974a28 100644 --- a/CAL/CalibrationCommon/lib/datacontainers/holography_dataset_definitions.py +++ b/CAL/CalibrationCommon/lib/datacontainers/holography_dataset_definitions.py @@ -18,6 +18,7 @@ HDS_ROTATION_MATRIX = "Rotation_matrix" HDS_ANTENNA_FIELD_POSITION = "Antenna_field_position" HDS_SPECIFIED_REFERENCE_STATION = "Specified_Reference_station" HDS_SPECIFIED_FREQUENCY = "Specified_frequency" +HDS_CENTRAL_BEAMLETS = "Central_beamlets" # GROUP "RA DEC" HDS_SPECIFIED_RA_DEC = "Specified_RA_DEC" -- GitLab