Ejemplo n.º 1
0
def test_node(check_gamit_tables=None, software_sync=()):
    # test node: function that makes sure that all required packages and tools are present in the nodes
    import traceback
    import platform
    import os
    import sys

    def check_tab_file(tabfile, date):
        if os.path.isfile(tabfile):
            # file exists, check contents
            with open(tabfile, 'rt', encoding='utf-8', errors='ignore') as f:
                lines = f.readlines()

            tabdate = pyDate.Date(mjd=lines[-1].split()[0])
            if tabdate < date:
                return ' -- %s: Last entry in %s is %s but processing %s' \
                       % (platform.node(), tabfile, tabdate.yyyyddd(), date.yyyyddd())
            return []
        else:
            return ' -- %s: Could not find file %s' % (platform.node(),
                                                       tabfile)

    # BEFORE ANYTHING! check the python version
    version = sys.version_info
    # if version.major > 2 or version.minor < 7 or (version.micro < 12 and version.minor <= 7):
    #     return ' -- %s: Incorrect Python version: %i.%i.%i. Recommended version >= 2.7.12' \
    #            % (platform.node(), version.major, version.minor, version.micro)
    if version.major < 3:
        return ' -- %s: Incorrect Python version: %i.%i.%i. Recommended version >= 3.0.0' \
               % (platform.node(), version.major, version.minor, version.micro)

    # start importing the modules needed
    try:
        import shutil
        import datetime
        import time
        import uuid
        import traceback
        # deps
        import numpy
        import pg
        import dirsync
        # app
        import pyRinex
        import dbConnection
        import pyStationInfo
        import pyArchiveStruct
        import pyPPP
        import pyBrdc
        import pyOptions
        import Utils
        import pyOTL
        import pySp3
        import pyETM
        import pyRunWithRetry
        import pyDate

    except:
        return ' -- %s: Problem found while importing modules:\n%s' % (
            platform.node(), traceback.format_exc())

    try:
        if len(software_sync) > 0:
            # synchronize directories listed in the src and dst arguments
            from dirsync import sync

            for source_dest in software_sync:
                if isinstance(source_dest, str) and ',' in source_dest:
                    s = source_dest.split(',')[0].strip()
                    d = source_dest.split(',')[1].strip()

                    print('    -- Synchronizing %s -> %s' % (s, d))

                    updated = sync(s, d, 'sync', purge=True, create=True)

                    for f in updated:
                        print('    -- Updated %s' % f)

    except:
        return ' -- %s: Problem found while synchronizing software:\n%s ' % (
            platform.node(), traceback.format_exc())

    # continue with a test SQL connection
    # make sure that the gnss_data.cfg is present
    try:
        cnn = dbConnection.Cnn('gnss_data.cfg')

        q = cnn.query('SELECT count(*) FROM networks')

        if int(pg.version[0]) < 5:
            return ' -- %s: Incorrect PyGreSQL version!: %s' % (
                platform.node(), pg.version)

    except:
        return ' -- %s: Problem found while connecting to postgres:\n%s ' % (
            platform.node(), traceback.format_exc())

    # make sure we can create the production folder
    try:
        test_dir = os.path.join('production/node_test')
        if not os.path.exists(test_dir):
            os.makedirs(test_dir)
    except:
        return ' -- %s: Could not create production folder:\n%s ' % (
            platform.node(), traceback.format_exc())

    # test
    try:
        Config = pyOptions.ReadOptions('gnss_data.cfg')

        # check that all paths exist and can be reached
        if not os.path.exists(Config.archive_path):
            return ' -- %s: Could not reach archive path %s' % (
                platform.node(), Config.archive_path)

        if not os.path.exists(Config.repository):
            return ' -- %s: Could not reach repository path %s' % (
                platform.node(), Config.repository)

        # pick a test date to replace any possible parameters in the config file
        date = pyDate.Date(year=2010, doy=1)

    except:
        return ' -- %s: Problem while reading config file and/or testing archive access:\n%s' \
               % (platform.node(), traceback.format_exc())

    try:
        brdc = pyBrdc.GetBrdcOrbits(Config.brdc_path, date, test_dir)
    except:
        return ' -- %s: Problem while testing the broadcast ephemeris archive (%s) access:\n%s' \
               % (platform.node(), Config.brdc_path, traceback.format_exc())

    try:
        sp3 = pySp3.GetSp3Orbits(Config.sp3_path, date, Config.sp3types,
                                 test_dir)
    except:
        return ' -- %s: Problem while testing the sp3 orbits archive (%s) access:\n%s' \
               % (platform.node(), Config.sp3_path, traceback.format_exc())

    # check that all executables and GAMIT bins are in the path
    for prg in ('crz2rnx', 'crx2rnx', 'rnx2crx', 'rnx2crz', 'gfzrnx_lx',
                'svdiff', 'svpos', 'tform', 'sh_rx2apr', 'doy', 'sed',
                'compress'):
        with pyRunWithRetry.command('which ' + prg) as run:
            run.run()
            if run.stdout == '':
                return ' -- %s: Could not find path to %s' % (platform.node(),
                                                              prg)

    # check grdtab and ppp from the config file
    for opt in ('grdtab', 'otlgrid', 'ppp_exe'):
        path = Config.options[opt]
        if not os.path.isfile(path):
            return ' -- %s: Could not find %s in %s' % (platform.node(), opt,
                                                        path)

    ppp_path = Config.options['ppp_path']
    for f in ('gpsppp.stc', 'gpsppp.svb_gps_yrly', 'gpsppp.flt', 'gpsppp.stc',
              'gpsppp.met'):
        if not os.path.isfile(os.path.join(ppp_path, f)):
            return ' -- %s: Could not find %s in %s' % (platform.node(), f,
                                                        ppp_path)

    for frame in Config.options['frames']:
        if not os.path.isfile(frame['atx']):
            return ' -- %s: Could not find atx in %s' % (platform.node(),
                                                         frame['atx'])

    if check_gamit_tables is not None:
        # check the gamit tables if not none

        date = check_gamit_tables[0]
        eop = check_gamit_tables[1]

        gg = os.path.expanduser('~/gg')
        tables = os.path.expanduser('~/gg/tables')

        if not os.path.isdir(gg):
            return ' -- %s: Could not GAMIT installation dir (gg)' % (
                platform.node())

        elif not os.path.isdir(tables):
            return ' -- %s: Could not GAMIT tables dir (gg)' % (
                platform.node())

        # DDG: deprecated -> GAMIT now uses a single nbody file (binary)
        # for t_name in ('luntab.' + date.yyyy() + '.J2000',
        #               'soltab.' + date.yyyy() + '.J2000',
        #               'ut1.' + eop,
        #               # leapseconds
        #               # vmf1
        #               'pole.' + eop
        #               ):
        #    result = check_tab_file(os.path.join(tables, t_name), date)
        #    if result:
        #        return result

        # fes_cmc consistency

    return ' -- %s: Test passed!' % platform.node()
Ejemplo n.º 2
0
def execute_ppp(rinexinfo,
                args,
                stnm,
                options,
                sp3types,
                sp3altrn,
                brdc_path,
                erase,
                apply_met=True,
                decimate=True):

    # put the correct APR coordinates in the header.
    # stninfo = pyStationInfo.StationInfo(None, allow_empty=True)
    stninfo = dict()

    brdc = pyBrdc.GetBrdcOrbits(brdc_path, rinexinfo.date, rinexinfo.rootdir)

    try:
        # inflate the chi**2 limit
        rinexinfo.purge_comments()
        rinexinfo.auto_coord(brdc=brdc, chi_limit=1000)
        rinexinfo.normalize_header(
            stninfo)  # empty dict: only applies the coordinate change
    except pyRinex.pyRinexException as e:
        print str(e)

    if args.load_rinex:
        rinexinfo.compress_local_copyto('./')
        print 'RINEX created in current directory.'
        return

    otl_coeff = ''

    try:
        if args.ocean_loading or args.insert_sql:
            # get a first ppp coordinate
            ppp = pyPPP.RunPPP(rinexinfo,
                               '',
                               options,
                               sp3types,
                               sp3altrn,
                               0,
                               strict=False,
                               apply_met=False,
                               kinematic=False,
                               clock_interpolation=True)

            ppp.exec_ppp()

            # use it to get the OTL (when the auto_coord is very bad, PPP doesn't like the resulting OTL).
            otl = pyOTL.OceanLoading(stnm, options['grdtab'],
                                     options['otlgrid'], ppp.x, ppp.y, ppp.z)
            otl_coeff = otl.calculate_otl_coeff()

            # run again, with OTL
            ppp = pyPPP.RunPPP(rinexinfo,
                               otl_coeff,
                               options,
                               sp3types,
                               sp3altrn,
                               0,
                               strict=False,
                               apply_met=apply_met,
                               kinematic=False,
                               clock_interpolation=True,
                               erase=erase,
                               decimate=decimate)
        else:
            ppp = pyPPP.RunPPP(rinexinfo,
                               '',
                               options,
                               sp3types,
                               sp3altrn,
                               0,
                               strict=False,
                               apply_met=apply_met,
                               kinematic=False,
                               clock_interpolation=True,
                               erase=erase,
                               decimate=decimate)

        ppp.exec_ppp()

        if not ppp.check_phase_center(ppp.proc_parameters):
            print 'WARNING: phase center parameters not found for declared antenna!'

        if not args.insert_sql:
            print '%s %10.5f %13.4f %13.4f %13.4f %14.9f %14.9f %8.3f' % (
                stnm, rinexinfo.date.fyear, ppp.x, ppp.y, ppp.z, ppp.lat[0],
                ppp.lon[0], ppp.h[0])
        else:
            print 'INSERT INTO stations ("NetworkCode", "StationCode", "auto_x", "auto_y", "auto_z", ' \
                  '"Harpos_coeff_otl", lat, lon, height) VALUES ' \
                  '(\'???\', \'%s\', %.4f, %.4f, %.4f, \'%s\', %.8f, %.8f, %.3f)' \
                  % (stnm, ppp.x, ppp.y, ppp.z, otl_coeff, ppp.lat[0], ppp.lon[0], ppp.h[0])

        if args.find:
            cnn = dbConnection.Cnn('gnss_data.cfg')

            Result, match, closest_stn = ppp.verify_spatial_coherence(
                cnn, stnm)

            if Result:
                print 'Found matching station: %s.%s' % (
                    match[0]['NetworkCode'], match[0]['StationCode'])

            elif not Result and len(match) == 1:

                print '%s matches the coordinate of %s.%s (distance = %8.3f m) but the filename indicates it is %s' \
                      % (rinexinfo.rinex, match[0]['NetworkCode'], match[0]['StationCode'],
                         float(match[0]['distance']), stnm)

            elif not Result and len(match) > 0:

                print 'Solution for RINEX (%s %s) did not match a unique station location (and station code) ' \
                      'within 10 km. Possible cantidate(s): %s' \
                      % (rinexinfo.rinex, rinexinfo.date.yyyyddd(), ', '.join(['%s.%s: %.3f m' %
                                                                               (m['NetworkCode'],
                                                                                m['StationCode'],
                                                                                m['distance']) for m in match]))

            elif not Result and len(match) == 0 and len(closest_stn) > 0:

                print 'No matches found. Closest station: %s.%s. (distance = %8.3f m)' \
                      % (closest_stn[0]['NetworkCode'], closest_stn[0]['StationCode'], closest_stn[0]['distance'])

    except pyPPP.pyRunPPPException as e:
        print 'Exception in PPP: ' + str(e)

    except pyRinex.pyRinexException as e:
        print 'Exception in pyRinex: ' + str(e)
Ejemplo n.º 3
0
    def start(self, dirname, year, doy, dry_run=False):

        monitor_open = False

        try:
            # copy the folder created by GamitSession in the solution_pwd to the remote_pwd (pwd)
            try:
                if not os.path.exists(os.path.dirname(self.pwd)):
                    os.makedirs(os.path.dirname(self.pwd))
            except OSError:
                # racing condition having several processes trying to create the same folder
                # if OSError occurs, ignore and continue
                pass

            # if the local folder exists (due to previous incomplete processing, erase it).
            if os.path.exists(self.pwd):
                shutil.rmtree(self.pwd)

            # ready to copy the shared solution_dir to pwd
            shutil.copytree(self.solution_pwd, self.pwd, symlinks=True)

            with open(os.path.join(self.pwd, 'monitor.log'), 'a') as monitor:

                monitor_open = True

                monitor.write(
                    datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                    ' -> %s %i %i executing on %s\n' %
                    (dirname, year, doy, platform.node()))

                monitor.write(
                    datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                    ' -> fetching orbits\n')

                try:
                    Sp3 = pySp3.GetSp3Orbits(self.orbits['sp3_path'],
                                             self.date,
                                             self.orbits['sp3types'],
                                             self.pwd_igs,
                                             True)  # type: pySp3.GetSp3Orbits

                except pySp3.pySp3Exception:

                    monitor.write(
                        datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                        ' -> could not find principal orbits, fetching alternative\n'
                    )

                    # try alternative orbits
                    if self.options['sp3altrn']:
                        Sp3 = pySp3.GetSp3Orbits(
                            self.orbits['sp3_path'], self.date,
                            self.orbits['sp3altrn'], self.pwd_igs,
                            True)  # type: pySp3.GetSp3Orbits
                    else:
                        raise

                if Sp3.type != 'igs':
                    # rename file
                    shutil.copyfile(Sp3.file_path,
                                    Sp3.file_path.replace(Sp3.type, 'igs'))

                monitor.write(
                    datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                    ' -> fetching broadcast orbits\n')

                pyBrdc.GetBrdcOrbits(
                    self.orbits['brdc_path'],
                    self.date,
                    self.pwd_brdc,
                    no_cleanup=True)  # type: pyBrdc.GetBrdcOrbits

                for rinex in self.params['rinex']:

                    monitor.write(
                        datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                        ' -> fetching rinex for %s.%s %s %s\n' %
                        (rinex['NetworkCode'], rinex['StationCode'],
                         rinex['StationAlias'], '{:10.6f} {:11.6f}'.format(
                             rinex['lat'], rinex['lon'])))

                    try:
                        with pyRinex.ReadRinex(
                                rinex['NetworkCode'], rinex['StationCode'],
                                rinex['source'],
                                False) as Rinex:  # type: pyRinex.ReadRinex

                            # WARNING! some multiday RINEX were generating conflicts because the RINEX has a name, say,
                            # tuc12302.10o and the program wants to rename it as tuc12030.10o but because it's a
                            # multiday file, during __init__ it's already split and renamed as tuc12300.10o and
                            # additional folders are generated with the information for each file. Therefore, find
                            # the rinex that corresponds to the date being processed and use that one instead of the
                            # original file. These files are not allowed by pyArchiveService, but the "start point" of
                            # the database (i.e. the files already in the folders read by pyScanArchive) has such
                            # problems.

                            # figure out if this station has been affected by an earthquake
                            # if so, window the data
                            if rinex['jump'] is not None:
                                monitor.write(
                                    '                    -> RINEX file has been windowed: ETM detected jump on '
                                    + rinex['jump'].datetime().strftime(
                                        '%Y-%m-%d %H:%M:%S') + '\n')

                            if Rinex.multiday:
                                # find the rinex that corresponds to the session being processed
                                for Rnx in Rinex.multiday_rnx_list:
                                    if Rnx.date == self.date:
                                        Rnx.rename(rinex['destiny'])

                                        if rinex['jump'] is not None:
                                            self.window_rinex(
                                                Rnx, rinex['jump'])
                                        # before creating local copy, decimate file
                                        Rnx.decimate(30)
                                        Rnx.purge_comments()
                                        Rnx.compress_local_copyto(
                                            self.pwd_rinex)
                                        break
                            else:
                                Rinex.rename(rinex['destiny'])

                                if rinex['jump'] is not None:
                                    self.window_rinex(Rinex, rinex['jump'])
                                # before creating local copy, decimate file
                                Rinex.decimate(30)
                                Rinex.purge_comments()
                                Rinex.compress_local_copyto(self.pwd_rinex)

                    except (OSError, IOError):
                        monitor.write(
                            datetime.datetime.now().strftime(
                                '%Y-%m-%d %H:%M:%S') +
                            ' -> An error occurred while trying to copy ' +
                            rinex['source'] + ' to ' + rinex['destiny'] +
                            ': File skipped.\n')

                    except (pyRinex.pyRinexException, Exception) as e:
                        monitor.write(
                            datetime.datetime.now().strftime(
                                '%Y-%m-%d %H:%M:%S') +
                            ' -> An error occurred while trying to copy ' +
                            rinex['source'] + ': ' + str(e) + '\n')

                monitor.write(
                    datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                    ' -> executing GAMIT\n')

                # create the run script
                self.create_replace_links()
                self.create_run_script()
                self.create_finish_script()

            # run the script to replace the links of the tables directory
            self.p = subprocess.Popen(
                'find ./tables ! -name "otl.grid" -type l -exec ./replace_links.sh {} +',
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                cwd=self.pwd)
            _, _ = self.p.communicate()

            # now execute the run script
            if not dry_run:
                self.p = subprocess.Popen('./run.sh',
                                          shell=False,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE,
                                          cwd=self.pwd)

                self.stdout, self.stderr = self.p.communicate()

                self.p = subprocess.Popen('./finish.sh',
                                          shell=False,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE,
                                          cwd=self.pwd)

                self.stdout, self.stderr = self.p.communicate()

                # check for any fatals
                self.p = subprocess.Popen('grep -q \'FATAL\' monitor.log',
                                          shell=True,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE,
                                          cwd=self.pwd)

                _, _ = self.p.communicate()

                if self.p.returncode == 0:
                    self.success = False
                else:
                    self.success = True

            # output statistics to the parent to display
            result = self.parse_monitor(self.success)

            with open(os.path.join(self.pwd, 'monitor.log'), 'a') as monitor:
                monitor.write(
                    datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                    ' -> return to Parallel.GAMIT\n')

            # no matter the result of the processing, move folder to final destination
            if not dry_run:
                self.finish()

            return result

        except Exception:

            msg = traceback.format_exc() + '\nProcessing %s date %s on node %s' \
                  % (self.params['NetName'], self.date.yyyyddd(), platform.node())

            # DDG: do not attempt to write to monitor.log or do any file operations (maybe permission problem)
            # problem might occur during copytree or rmtree or some other operation before opening monitor.log
            if monitor_open:
                with open(os.path.join(self.pwd, 'monitor.log'),
                          'a') as monitor:
                    monitor.write(
                        datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +
                        ' -> ERROR in pyGamitTask.start()\n%s' % msg)

                # the solution folder exists because it was created by GamitSession to start the processing.
                # erase it to upload the result
                if os.path.exists(self.solution_pwd):
                    shutil.rmtree(self.solution_pwd)

                # execute final error step: copy to self.solution_pwd
                shutil.copytree(self.pwd, self.solution_pwd, symlinks=True)
                # remove the remote pwd
                shutil.rmtree(self.pwd)

                # output statistics to the parent to display
                result = self.parse_monitor(False)
            else:
                result = {
                    'session':
                    '%s %s' % (self.date.yyyyddd(), self.params['DirName']),
                    'Project':
                    self.params['NetName'],
                    'subnet':
                    self.params['subnet'],
                    'Year':
                    self.date.year,
                    'DOY':
                    self.date.doy,
                    'FYear':
                    self.date.fyear,
                    'wl':
                    0,
                    'nl':
                    0,
                    'nrms':
                    0,
                    'relaxed_constrains':
                    '',
                    'max_overconstrained':
                    '',
                    'node':
                    platform.node(),
                    'execution_time':
                    0,
                    'execution_date':
                    0,
                    'missing':
                    '',
                    'success':
                    False,
                    'fatals': []
                }

            result['error'] = msg

            # return useful information to the main node
            return result
Ejemplo n.º 4
0
def process_crinex_file(crinez, filename, data_rejected, data_retry):

    # create a uuid temporary folder in case we cannot read the year and doy from the file (and gets rejected)
    reject_folder = os.path.join(data_rejected, str(uuid.uuid4()))

    try:
        cnn = dbConnection.Cnn("gnss_data.cfg")
        Config = pyOptions.ReadOptions("gnss_data.cfg")
        archive = pyArchiveStruct.RinexStruct(cnn)
        # apply local configuration (path to repo) in the executing node
        crinez = os.path.join(Config.repository_data_in, crinez)

    except Exception:

        return traceback.format_exc() + ' while opening the database to process file ' + \
               crinez + ' node ' + platform.node(), None

    # assume a default networkcode
    NetworkCode = 'rnx'
    # get the station code year and doy from the filename
    fileparts = archive.parse_crinex_filename(filename)

    if fileparts:
        StationCode = fileparts[0].lower()
        doy = int(fileparts[1])
        year = int(Utils.get_norm_year_str(fileparts[3]))
    else:
        event = pyEvents.Event(
            Description='Could not read the station code, year or doy for file '
            + crinez,
            EventType='error')
        error_handle(cnn,
                     event,
                     crinez,
                     reject_folder,
                     filename,
                     no_db_log=True)
        return event['Description'], None

    # we can now make better reject and retry folders
    reject_folder = os.path.join(
        data_rejected, '%reason%/' + Utils.get_norm_year_str(year) + '/' +
        Utils.get_norm_doy_str(doy))

    retry_folder = os.path.join(
        data_retry, '%reason%/' + Utils.get_norm_year_str(year) + '/' +
        Utils.get_norm_doy_str(doy))

    try:
        # main try except block
        with pyRinex.ReadRinex(NetworkCode, StationCode,
                               crinez) as rinexinfo:  # type: pyRinex.ReadRinex

            # STOP! see if rinexinfo is a multiday rinex file
            if not verify_rinex_multiday(cnn, rinexinfo, Config):
                # was a multiday rinex. verify_rinex_date_multiday took care of it
                return None, None

            # DDG: we don't use otl coefficients because we need an approximated coordinate
            # we therefore just calculate the first coordinate without otl
            # NOTICE that we have to trust the information coming in the RINEX header (receiver type, antenna type, etc)
            # we don't have station info data! Still, good enough
            # the final PPP coordinate will be calculated by pyScanArchive on a different process

            # make sure that the file has the appropriate coordinates in the header for PPP.
            # put the correct APR coordinates in the header.
            # ppp didn't work, try using sh_rx2apr
            brdc = pyBrdc.GetBrdcOrbits(Config.brdc_path, rinexinfo.date,
                                        rinexinfo.rootdir)

            # inflate the chi**2 limit to make sure it will pass (even if we get a crappy coordinate)
            try:
                rinexinfo.auto_coord(brdc, chi_limit=1000)

                # normalize header to add the APR coordinate
                # empty dict since nothing extra to change (other than the APR coordinate)
                rinexinfo.normalize_header(dict())
            except pyRinex.pyRinexExceptionNoAutoCoord:
                # could not determine an autonomous coordinate, try PPP anyways. 50% chance it will work
                pass

            with pyPPP.RunPPP(
                    rinexinfo,
                    '',
                    Config.options,
                    Config.sp3types,
                    Config.sp3altrn,
                    rinexinfo.antOffset,
                    strict=False,
                    apply_met=False,
                    clock_interpolation=True) as ppp:  # type: pyPPP.RunPPP

                try:
                    ppp.exec_ppp()

                except pyPPP.pyRunPPPException as ePPP:

                    # inflate the chi**2 limit to make sure it will pass (even if we get a crappy coordinate)
                    # if coordinate is TOO bad it will get kicked off by the unreasonable geodetic height
                    try:
                        auto_coords_xyz, auto_coords_lla = rinexinfo.auto_coord(
                            brdc, chi_limit=1000)

                    except pyRinex.pyRinexExceptionNoAutoCoord as e:
                        # catch pyRinexExceptionNoAutoCoord and convert it into a pyRunPPPException

                        raise pyPPP.pyRunPPPException(
                            'Both PPP and sh_rx2apr failed to obtain a coordinate for %s.\n'
                            'The file has been moved into the rejection folder. '
                            'Summary PPP file and error (if exists) follows:\n%s\n\n'
                            'ERROR section:\n%s\npyRinex.auto_coord error follows:\n%s'
                            % (crinez.replace(Config.repository_data_in, ''),
                               ppp.summary, str(ePPP).strip(), str(e).strip()))

                    # DDG: this is correct - auto_coord returns a numpy array (calculated in ecef2lla),
                    # so ppp.lat = auto_coords_lla is consistent.
                    ppp.lat = auto_coords_lla[0]
                    ppp.lon = auto_coords_lla[1]
                    ppp.h = auto_coords_lla[2]
                    ppp.x = auto_coords_xyz[0]
                    ppp.y = auto_coords_xyz[1]
                    ppp.z = auto_coords_xyz[2]

                # check for unreasonable heights
                if ppp.h[0] > 9000 or ppp.h[0] < -400:
                    raise pyRinex.pyRinexException(
                        os.path.relpath(crinez, Config.repository_data_in) +
                        ' : unreasonable geodetic height (%.3f). '
                        'RINEX file will not enter the archive.' % (ppp.h[0]))

                Result, match, _ = ppp.verify_spatial_coherence(
                    cnn, StationCode)

                if Result:
                    # insert: there is only 1 match with the same StationCode.
                    rinexinfo.rename(NetworkCode=match[0]['NetworkCode'])
                    insert_data(cnn, archive, rinexinfo)
                else:

                    if len(match) == 1:
                        error = "%s matches the coordinate of %s.%s (distance = %8.3f m) but the filename " \
                                "indicates it is %s. Please verify that this file belongs to %s.%s, rename it and " \
                                "try again. The file was moved to the retry folder. " \
                                "Rename script and pSQL sentence follows:\n" \
                                "BASH# mv %s %s\n" \
                                "PSQL# INSERT INTO stations (\"NetworkCode\", \"StationCode\", \"auto_x\", " \
                                "\"auto_y\", \"auto_z\", \"lat\", \"lon\", \"height\") VALUES " \
                                "('???','%s', %12.3f, %12.3f, %12.3f, " \
                                "%10.6f, %10.6f, %8.3f)\n" \
                                % (os.path.relpath(crinez, Config.repository_data_in), match[0]['NetworkCode'],
                                   match[0]['StationCode'], float(match[0]['distance']), StationCode,
                                   match[0]['NetworkCode'], match[0]['StationCode'],
                                   os.path.join(retry_folder, filename),
                                   os.path.join(retry_folder, filename.replace(StationCode, match[0]['StationCode'])),
                                   StationCode, ppp.x, ppp.y, ppp.z, ppp.lat[0], ppp.lon[0], ppp.h[0])

                        raise pyPPP.pyRunPPPExceptionCoordConflict(error)

                    elif len(match) > 1:
                        # a number of things could have happened:
                        # 1) wrong station code, and more than one matching stations
                        #    (that do not match the station code, of course)
                        #    see rms.lhcl 2007 113 -> matches rms.igm0: 34.293 m, rms.igm1: 40.604 m, rms.byns: 4.819 m
                        # 2) no entry in the database for this solution -> add a lock and populate the exit args

                        # no match, but we have some candidates

                        error = "Solution for RINEX in repository (%s %s) did not match a unique station location " \
                                "(and station code) within 5 km. Possible cantidate(s): %s. This file has been moved " \
                                "to data_in_retry. pSQL sentence follows:\n" \
                                "PSQL# INSERT INTO stations (\"NetworkCode\", \"StationCode\", \"auto_x\", " \
                                "\"auto_y\", \"auto_z\", \"lat\", \"lon\", \"height\") VALUES " \
                                "('???','%s', %12.3f, %12.3f, %12.3f, %10.6f, %10.6f, %8.3f)\n" \
                                % (os.path.relpath(crinez, Config.repository_data_in), rinexinfo.date.yyyyddd(),
                                   ', '.join(['%s.%s: %.3f m' %
                                              (m['NetworkCode'], m['StationCode'], m['distance']) for m in match]),
                                   StationCode, ppp.x, ppp.y, ppp.z, ppp.lat[0], ppp.lon[0], ppp.h[0])

                        raise pyPPP.pyRunPPPExceptionCoordConflict(error)

                    else:
                        # only found a station removing the distance limit (could be thousands of km away!)

                        # The user will have to add the metadata to the database before the file can be added,
                        # but in principle no problem was detected by the process. This file will stay in this folder
                        # so that it gets analyzed again but a "lock" will be added to the file that will have to be
                        # removed before the service analyzes again.
                        # if the user inserted the station by then, it will get moved to the appropriate place.
                        # we return all the relevant metadata to ease the insert of the station in the database

                        otl = pyOTL.OceanLoading(StationCode,
                                                 Config.options['grdtab'],
                                                 Config.options['otlgrid'])
                        # use the ppp coordinates to calculate the otl
                        coeff = otl.calculate_otl_coeff(x=ppp.x,
                                                        y=ppp.y,
                                                        z=ppp.z)

                        # add the file to the locks table so that it doesn't get processed over and over
                        # this will be removed by user so that the file gets reprocessed once all the metadata is ready
                        cnn.insert('locks',
                                   filename=os.path.relpath(
                                       crinez, Config.repository_data_in))

                        return None, [
                            StationCode, (ppp.x, ppp.y, ppp.z), coeff,
                            (ppp.lat[0], ppp.lon[0], ppp.h[0]), crinez
                        ]

    except (pyRinex.pyRinexExceptionBadFile, pyRinex.pyRinexExceptionSingleEpoch, pyRinex.pyRinexExceptionNoAutoCoord) \
            as e:

        reject_folder = reject_folder.replace('%reason%', 'bad_rinex')

        # add more verbose output
        e.event['Description'] = e.event['Description'] + '\n' + os.path.relpath(crinez, Config.repository_data_in) + \
                                 ': (file moved to ' + reject_folder + ')'
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy
        # error, move the file to rejected folder
        error_handle(cnn, e.event, crinez, reject_folder, filename)

        return None, None

    except pyRinex.pyRinexException as e:

        retry_folder = retry_folder.replace('%reason%', 'rinex_issues')

        # add more verbose output
        e.event['Description'] = e.event['Description'] + '\n' + os.path.relpath(crinez, Config.repository_data_in) + \
                                 ': (file moved to ' + retry_folder + ')'
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy
        # error, move the file to rejected folder
        error_handle(cnn, e.event, crinez, retry_folder, filename)

        return None, None

    except pyPPP.pyRunPPPExceptionCoordConflict as e:

        retry_folder = retry_folder.replace('%reason%', 'coord_conflicts')

        e.event['Description'] = e.event['Description'].replace(
            '%reason%', 'coord_conflicts')

        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, retry_folder, filename)

        return None, None

    except pyPPP.pyRunPPPException as e:

        reject_folder = reject_folder.replace('%reason%', 'no_ppp_solution')

        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, reject_folder, filename)

        return None, None

    except pyStationInfo.pyStationInfoException as e:

        retry_folder = retry_folder.replace('%reason%',
                                            'station_info_exception')

        e.event['Description'] = e.event['Description'] + '. The file will stay in the repository and will be ' \
                                                          'processed during the next cycle of pyArchiveService.'
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, retry_folder, filename)

        return None, None

    except pyOTL.pyOTLException as e:

        retry_folder = retry_folder.replace('%reason%', 'otl_exception')

        e.event['Description'] = e.event['Description'] + ' while calculating OTL for %s. ' \
                                                          'The file has been moved into the retry folder.' \
                                                          % os.path.relpath(crinez, Config.repository_data_in)
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, retry_folder, filename)

        return None, None

    except pyProducts.pyProductsExceptionUnreasonableDate as e:
        # a bad RINEX file requested an orbit for a date < 0 or > now()
        reject_folder = reject_folder.replace('%reason%', 'bad_rinex')

        e.event['Description'] = e.event['Description'] + ' during %s. The file has been moved to the rejected ' \
                                                          'folder. Most likely bad RINEX header/data.' \
                                                          % os.path.relpath(crinez, Config.repository_data_in)
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, reject_folder, filename)

        return None, None

    except pyProducts.pyProductsException as e:

        # if PPP fails and ArchiveService tries to run sh_rnx2apr and it doesn't find the orbits, send to retry
        retry_folder = retry_folder.replace('%reason%', 'sp3_exception')

        e.event['Description'] = e.event['Description'] + ': %s. Check the brdc/sp3/clk files and also check that ' \
                                                          'the RINEX data is not corrupt.' \
                                                          % os.path.relpath(crinez, Config.repository_data_in)
        e.event['StationCode'] = StationCode
        e.event['NetworkCode'] = '???'
        e.event['Year'] = year
        e.event['DOY'] = doy

        error_handle(cnn, e.event, crinez, retry_folder, filename)

        return None, None

    except dbConnection.dbErrInsert as e:

        reject_folder = reject_folder.replace('%reason%', 'duplicate_insert')

        # insert duplicate values: two parallel processes tried to insert different filenames
        # (or the same) of the same station to the db: move it to the rejected folder.
        # The user might want to retry later. Log it in events
        # this case should be very rare
        event = pyEvents.Event(
            Description='Duplicate rinex insertion attempted while processing '
            + os.path.relpath(crinez, Config.repository_data_in) +
            ' : (file moved to rejected folder)\n' + str(e),
            EventType='warn',
            StationCode=StationCode,
            NetworkCode='???',
            Year=year,
            DOY=doy)

        error_handle(cnn, event, crinez, reject_folder, filename)

        return None, None

    except Exception:

        retry_folder = retry_folder.replace('%reason%', 'general_exception')

        event = pyEvents.Event(
            Description=traceback.format_exc() + ' processing: ' +
            os.path.relpath(crinez, Config.repository_data_in) + ' in node ' +
            platform.node() + ' (file moved to retry folder)',
            EventType='error')

        error_handle(cnn,
                     event,
                     crinez,
                     retry_folder,
                     filename,
                     no_db_log=True)

        return event['Description'], None

    return None, None
Ejemplo n.º 5
0
def execute_ppp(rinexinfo,
                args,
                stnm,
                options,
                sp3types,
                sp3altrn,
                brdc_path,
                erase,
                apply_met=True,
                decimate=True,
                fix_coordinate=None,
                solve_troposphere=105,
                copy_results=None,
                backward_substitution=False,
                elevation_mask=5):

    # put the correct APR coordinates in the header.
    # stninfo = pyStationInfo.StationInfo(None, allow_empty=True)
    brdc = pyBrdc.GetBrdcOrbits(brdc_path, rinexinfo.date, rinexinfo.rootdir)

    try:
        # inflate the chi**2 limit
        rinexinfo.purge_comments()
        rinexinfo.auto_coord(brdc=brdc, chi_limit=1000)
        stninfo = {}
        rinexinfo.normalize_header(
            stninfo)  # empty dict: only applies the coordinate change
    except pyRinex.pyRinexException as e:
        print(str(e))

    if args.load_rinex:
        rinexinfo.compress_local_copyto('./')
        print('RINEX created in current directory.')
        return

    try:
        otl_coeff = ''

        if args.ocean_loading or args.insert_sql:
            # get a first ppp coordinate
            ppp = pyPPP.RunPPP(rinexinfo,
                               '',
                               options,
                               sp3types,
                               sp3altrn,
                               0,
                               strict=False,
                               apply_met=False,
                               kinematic=False,
                               clock_interpolation=True)

            ppp.exec_ppp()

            # use it to get the OTL (when the auto_coord is very bad, PPP doesn't like the resulting OTL).
            otl = pyOTL.OceanLoading(stnm, options['grdtab'],
                                     options['otlgrid'], ppp.x, ppp.y, ppp.z)
            otl_coeff = otl.calculate_otl_coeff()
            # run again, now with OTL coeff:

        # determine if need to solve for coordinates or not
        x = y = z = 0
        if fix_coordinate is not None:
            if len(fix_coordinate) > 1:
                x = float(fix_coordinate[0])
                y = float(fix_coordinate[1])
                z = float(fix_coordinate[2])
            else:
                # read from file
                cstr = file_readlines(fix_coordinate[0])
                xyz = re.findall(
                    r'%s (-?\d+\.\d+)\s+(-?\d+\.\d+)\s+(-?\d+\.\d+)' %
                    rinexinfo.StationCode, ''.join(cstr), re.IGNORECASE)
                if len(xyz):
                    x = float(xyz[0][0])
                    y = float(xyz[0][1])
                    z = float(xyz[0][2])
                else:
                    print(
                        'WARNING: coordinate fixing invoked but could not find %s in list of coordinates -> '
                        'unfixing station coordinate in PPP' %
                        rinexinfo.StationCode)
                    fix_coordinate = False
            print('%14.4f %14.4f %14.4f' % (x, y, z))

        ppp = pyPPP.RunPPP(
            rinexinfo,
            otl_coeff,
            options,
            sp3types,
            sp3altrn,
            0,
            strict=False,
            apply_met=apply_met,
            kinematic=False,
            clock_interpolation=True,
            erase=erase,
            decimate=decimate,
            solve_coordinates=True if not fix_coordinate else False,
            solve_troposphere=solve_troposphere,
            back_substitution=backward_substitution,
            elev_mask=elevation_mask,
            x=x,
            y=y,
            z=z)

        ppp.exec_ppp()

        if not ppp.check_phase_center(ppp.proc_parameters):
            print(
                'WARNING: phase center parameters not found for declared antenna!'
            )

        if not args.insert_sql:
            print(
                '%s %10.5f %13.4f %13.4f %13.4f %14.9f %14.9f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f'
                %
                (stnm, rinexinfo.date.fyear, ppp.x, ppp.y, ppp.z, ppp.lat[0],
                 ppp.lon[0], ppp.h[0], ppp.clock_phase, ppp.clock_phase_sigma,
                 ppp.phase_drift, ppp.phase_drift_sigma, ppp.clock_rms))
        else:
            print('INSERT INTO stations ("NetworkCode", "StationCode", "auto_x", "auto_y", "auto_z", ' \
                  '"Harpos_coeff_otl", lat, lon, height) VALUES ' \
                  '(\'???\', \'%s\', %.4f, %.4f, %.4f, \'%s\', %.8f, %.8f, %.3f)' \
                  % (stnm, ppp.x, ppp.y, ppp.z, otl_coeff, ppp.lat[0], ppp.lon[0], ppp.h[0]))

        if args.find:
            cnn = dbConnection.Cnn('gnss_data.cfg')

            Result, match, closest_stn = ppp.verify_spatial_coherence(
                cnn, stnm)

            if Result:
                print('Found matching station: %s.%s' %
                      (match[0]['NetworkCode'], match[0]['StationCode']))

            elif len(match) == 1:
                print('%s matches the coordinate of %s.%s (distance = %8.3f m) but the filename indicates it is %s' \
                      % (rinexinfo.rinex,
                         match[0]['NetworkCode'],
                         match[0]['StationCode'],
                         float(match[0]['distance']),
                         stnm))

            elif len(match) > 0:
                print('Solution for RINEX (%s %s) did not match a unique station location (and station code) ' \
                      'within 10 km. Possible cantidate(s): %s' \
                      % (rinexinfo.rinex,
                         rinexinfo.date.yyyyddd(),
                         ', '.join(['%s.%s: %.3f m' %
                                    (m['NetworkCode'],
                                     m['StationCode'],
                                     m['distance']) for m in match])))

            elif len(match) == 0 and len(closest_stn) > 0:
                print('No matches found. Closest station: %s.%s. (distance = %8.3f m)' \
                      % (closest_stn[0]['NetworkCode'],
                         closest_stn[0]['StationCode'],
                         closest_stn[0]['distance']))

        if copy_results:
            copy_results = copy_results[0]
            try:
                fpath = os.path.join(copy_results, rinexinfo.StationCode)
                if not os.path.exists(fpath):
                    os.makedirs(fpath)
                shutil.copyfile(
                    ppp.path_res_file,
                    os.path.join(fpath, os.path.basename(ppp.path_res_file)))
                shutil.copyfile(
                    ppp.path_pos_file,
                    os.path.join(fpath, os.path.basename(ppp.path_pos_file)))
                shutil.copyfile(
                    ppp.path_ses_file,
                    os.path.join(fpath, os.path.basename(ppp.path_ses_file)))
                shutil.copyfile(
                    ppp.path_sum_file,
                    os.path.join(fpath, os.path.basename(ppp.path_sum_file)))
                shutil.copyfile(
                    os.path.join(ppp.rootdir, 'commands.cmd'),
                    os.path.join(fpath,
                                 os.path.basename(ppp.path_sum_file) + '.cmd'))
            except Exception as e:
                print(
                    'WARNING: There was a problem copying results to %s: %s' %
                    (copy_results, str(e)))

    except pyPPP.pyRunPPPException as e:
        print('Exception in PPP: ' + str(e))

    except pyRinex.pyRinexException as e:
        print('Exception in pyRinex: ' + str(e))