Exemple #1
0
def rinex_obs(**parser_args: Any) -> parsers.RinexParser:
    """Dispatch to correct subclass based on version in Rinex file"""

    # Import parsers locally to avoid circular imports
    from midgard.parsers import wip_rinex2_obs as rinex2_obs, wip_rinex3_obs as rinex3_obs

    _PARSERS = {
        "2": rinex2_obs.Rinex2ObsParser,
        "3": rinex3_obs.Rinex3ObsParser
    }

    # Run a basic rinex parser to info from file
    parser = parsers.RinexParser(**parser_args)
    rinex_info = parser.get_rinex_version_type()

    if rinex_info["file_type"] != "O":
        raise exceptions.ParserError(
            f"File {parser.file_path} is a {rinex_info['file_type']!r} file, expected 'O'"
        )

    version = rinex_info["rinex_version"][0]  # Major version

    try:
        return _PARSERS[version](**parser_args)
    except KeyError:
        raise exceptions.ParserError(
            f"File {parser.file_path} is version {rinex_info['rinex_version']}, "
            f"which is not supported")
Exemple #2
0
    def read_data(self) -> None:
        """Dispatch to correct subclass based on version in Rinex file

        Need to make sure the dispatch only happens for RinexObsParsers, not for subclasses.
        """
        if self.__class__.__name__ == "RinexObsParser":
            Parser: Type[parsers.RinexParser]

            # Find correct parser subclass
            version = self.get_rinex_version()
            if version.startswith("3"):
                from midgard.parsers.rinex3_obs import Rinex3ObsParser

                Parser = Rinex3ObsParser
            elif version.startswith("2"):
                from midgard.parsers.rinex2_obs import Rinex2ObsParser

                Parser = Rinex2ObsParser
            else:
                raise exceptions.ParserError(
                    f"Unknown version {version!r} for Rinex observation files")

            # Read data with correct parser
            parser = Parser(**self.meta["__kwargs__"])
            parser.read_data()

            # Copy data to self
            self.header.update(parser.header)
            self.data.update(parser.data)

        else:
            super().read_data()
Exemple #3
0
def rinex(**parser_args: Any) -> parsers.RinexParser:
    """Dispatch to correct subclass based on Rinex file type"""
    parser = parsers.RinexParser(**parser_args)
    rinex_info = parser.get_rinex_version_type()

    if rinex_info["file_type"] not in _PARSERS.keys():
        raise exceptions.ParserError(
            f"File {parser.file_path} is a {rinex_info['file_type']!r} file, "
            f"expected {' '.join(_PARSERS.keys())}")

    file_type = rinex_info["file_type"]

    try:
        return _PARSERS[file_type](**parser_args)
    except KeyError:
        raise exceptions.ParserError(
            f"File {parser.file_path} has file type {rinex_info['file_type']}, which is not supported"
        )
Exemple #4
0
    def get_rinex_version(self) -> str:
        """Get version of Rinex file"""
        version = self.rinex_version__type

        with open(self.file_path, mode="r", encoding=self.file_encoding) as fid:
            for line in fid:
                marker = line[60:80].strip()
                if marker != version.marker:
                    self.error(f"Wrong marker {marker!r} before version information")
                    continue
                return line[slice(*version.fields["rinex_version"])].strip()

        raise exceptions.ParserError(f"No information about Rinex version found in {self.file_path}")
Exemple #5
0
    def get_rinex_version_type(self) -> Dict[str, str]:
        """Get version and type of Rinex file"""
        header_def = self.rinex_version__type

        with open(self.file_path, mode="r", encoding=self.file_encoding) as fid:
            for line in fid:
                marker = line[60:80].strip()
                if marker != header_def.marker:
                    self.error(f"Wrong marker {marker!r} before version information")
                    continue
                return {k: line[slice(*v)].strip() for k, v in header_def.fields.items()}

        raise exceptions.ParserError(f"No information about Rinex version found in {self.file_path}")
Exemple #6
0
 def _raise_error(self, text: str) -> None:
     """Raise a parser error"""
     raise exceptions.ParserError(text)
Exemple #7
0
    def save_correction(self, line: Dict[str, str], cache: Dict[str,
                                                                Any]) -> None:
        """Save antenna correction in data structures.

        The antenna corrections are saved after reading of corrections for one frequency. Antenna correction data are
        saved in following data structure, whereby satellite antenna corrections are time dependent:

            self.data = { <prn> : { <valid from>: { cospar_id:   <value>,
                                                    sat_code:    <value>,
                                                    sat_type:    <value>,
                                                    valid_until: <value>,
                                                    azimuth:     <list with azimuth values>,
                                                    elevation:   <list with elevation values>,
                                                    <frequency>: { azi: [<list with azimuth-elevation dependent corrections>],
                                                                   neu: [north, east, up],
                                                                   noazi: [<list with elevation dependent corrections>] }}},

                          <receiver antenna> : { azimuth:     <list with azimuth values>,
                                                 elevation:   <list with elevation values>,
                                                 <frequency>: { azi: [<array with azimuth-elevation dependent corrections>],
                                                                neu: [north, east, up],
                                                                noazi: [<list with elevation dependent corrections>] }}
                        }

        """
        ant = cache["antenna_code"] if cache["sat_code"] else cache[
            "antenna_type"]
        self.data.setdefault(ant, dict())
        freq = cache["frequency_code"]
        if "valid_from" in cache:
            dt = cache["valid_from"]
        tmp: Dict[str, Any] = dict(
        )  # Temporary dictionary, where antenna correction for one frequency is saved.
        tmp[freq] = dict()

        # Save general information of ANTEX antenna section (NOTE: Has to be done only once.)
        if cache["num_freq_counter"] == 0:

            if cache["sat_code"]:  # only necessary for satellites
                if dt in self.data[ant]:
                    valid_from = "{:4d}-{:02d}-{:02d}".format(
                        dt.year, dt.month, dt.day)
                    raise exceptions.ParserError(
                        f"Antenna correction for satellite PRN {ant} (SVN {cache['sat_code']}) valid "
                        f"from {valid_from} is not unique.")

                tmp["cospar_id"] = cache["cospar_id"]
                tmp["sat_code"] = cache["sat_code"]
                tmp["sat_type"] = cache["antenna_type"]
                if "valid_until" in cache:
                    tmp["valid_until"] = cache["valid_until"]
                else:
                    tmp["valid_until"] = datetime.datetime.now()

            # Determine elevation list
            if cache["dzen"] != 0.0:
                tmp["elevation"] = np.arange(
                    90.0 - cache["zen1"],
                    90.0 - (cache["zen2"] + cache["dzen"]), -cache["dzen"])
                tmp["elevation"] = np.radians(tmp["elevation"])

            # Determine azimuth list
            if cache["dazi"] != 0.0:
                tmp["azimuth"] = np.arange(0, 360 + cache["dazi"],
                                           cache["dazi"])
                tmp["azimuth"] = np.radians(tmp["azimuth"])

        # Save frequency dependent antenna corrections
        tmp[freq]["neu"] = [
            cache["north"] * Unit.millimeter2meter,
            cache["east"] * Unit.millimeter2meter,
            cache["up"] * Unit.millimeter2meter,
        ]
        tmp[freq]["noazi"] = np.array(cache["noazi"])
        if "azi" in cache:
            tmp[freq]["azi"] = np.array(cache["azi"])

        # Save satellite antenna correction in data structure
        if cache["sat_code"]:
            self.data[ant].setdefault(dt, dict())

            if freq in self.data[ant][dt]:
                valid_from = "{:4d}-{:02d}-{:02d}".format(
                    dt.year, dt.month, dt.day)
                raise exceptions.ParserError(
                    f"Frequency {freq} antenna corrections for satellite PRN {ant} valid from {valid_from} is "
                    f"not unique in file {self.file_path}.")

            self.data[ant][dt].update(tmp)

        # Save receiver antenna correction in data structure
        else:
            if freq in self.data[ant]:
                raise exceptions.ParserError(
                    f"Frequency {freq} antenna corrections for receiver antenna {ant} is not unique "
                    f"in file {self.file_path}.")

            self.data[ant].update(tmp)

        cache["num_freq_counter"] = cache["num_freq_counter"] + 1