Example #1
0
    def _build_antenna_array(self):
        """
        Update the internal observer and antenna array information if and only
        if both the set_frequency and set_geometry methods have been called.
        """

        try:
            assert (len(self.freq) > 0)
            self.site
            self.antennas
        except (AssertionError, AttributeError):
            return False

        # Convert the reference time to a JD
        ref_time = datetime.strptime(self.ref_time, "%Y-%m-%dT%H:%M:%S")
        mjd, mpm = datetime_to_mjdmpm(ref_time)
        ref_jd = mjd + mpm / 1000.0 / 86400 + astro.MJD_OFFSET

        # Create the observer and antenna array
        self.observer = self.site.get_observer()
        self.antenna_array = build_sim_array(self.site,
                                             self.antennas,
                                             self.freq / 1e9,
                                             jd=ref_jd)

        return True
Example #2
0
 def test_datetime(self):
     """Test the datetime to MJD, MPM conversion"""
     
     dt = datetime.strptime("2012-06-15 06:34:09", "%Y-%m-%d %H:%M:%S")
     mjd, mpm = mcs.datetime_to_mjdmpm(dt)
     
     self.assertEqual(mjd, 56093)
     self.assertEqual(mpm, 23649000)
Example #3
0
def mjd(string):
    """
    Convert a data as either a YYYY[-/]MM[-/]DD or MJD string into an integer
    MJD.
    """

    try:
        mjd = int(string, 10)
    except ValueError:
        cstring = string.replace('-', '/')
        try:
            dt = datetime.strptime("%s 00:00:00" % cstring,
                                   "%Y/%m/%d %H:%M:%S")
            mjd, mpm = datetime_to_mjdmpm(dt)
        except ValueError:
            msg = "%r cannot be interpretted as an MJD or date string" % string
            raise ArgumentTypeError(msg)

    return mjd
Example #4
0
def mpm(string):
    """
    Covnert a time as HH:MM:SS[.SSS] or MPM string into an MPM integer.
    """

    try:
        mpm = int(string, 10)
        if mpm < 0 or mpm > (86400 * 1000 + 999):
            msg = "%r is out of range for an MPM value"
            raise ArgumentTypeError(msg)
    except ValueError:
        try:
            dt = datetime.strptime("2000/1/1 %s" % string,
                                   "%Y/%m/%d %H:%M:%S.%f")
        except ValueError:
            try:
                dt = datetime.strptime("2000/1/1 %s" % string,
                                       "%Y/%m/%d %H:%M:%S")
            except ValueError:
                msg = "%r cannot be interpretted as a time string" % string
                raise ArgumentTypeError(msg)
        mjd, mpm = datetime_to_mjdmpm(dt)
    return mpm
Example #5
0
def main(args):
    # Inputs
    if args.file is not None:
        mjdList = numpy.loadtxt(args.file)
        mjdList = mjdList.ravel()
        
        mjdList = numpy.sort(mjdList)
        
    else:
        tStart = "%s %s" % (args.StartDate, args.StartTime)
        tStop = "%s %s" % (args.StopDate, args.StopTime)
        
        # YYYY/MM/DD HH:MM:SS -> datetime instance
        tStart = datetime.strptime(tStart, "%Y/%m/%d %H:%M:%S.%f")
        tStop = datetime.strptime(tStop, "%Y/%m/%d %H:%M:%S.%f")
        
        # datetime instance to MJD
        mjd,mpm = datetime_to_mjdmpm(tStart)
        mjdStart = mjd + mpm/1000.0/86400.0
        mjd,mpm = datetime_to_mjdmpm(tStop)
        mjdStop = mjd + mpm/1000.0/86400.0
        
        mjdList = numpy.linspace(mjdStart, mjdStop, args.n_samples)
    
    # Setup everything for computing the position of the source
    if args.lwasv:
        site = stations.lwasv
    elif args.ovrolwa:
        site = stations.lwa1
        site.lat, site.lon, site.elev = ('37.23977727', '-118.2816667', 1182.89)
    else:
        site = stations.lwa1
    obs = site.get_observer()
    bdy = ephem.FixedBody()
    bdy._ra = args.RA
    bdy._dec = args.Dec
    
    # Setup the ionospheric model source
    if args.igs:
        mtype = 'IGS'
    elif args.jpl:
        mtype = 'JPL'
    elif args.code:
        mtype = 'CODE'
    elif args.ustec:
        mtype = 'USTEC'
    elif args.uqr:
        mtype = 'UQR'
    else:
        mtype = 'IGS'
    
    # Go!
    print("%-13s  %-6s  %-6s  %-21s  %-15s" % ("MJD", "Az.", "El.", "DM [pc/cm^3]", "RM [1/m^2]"))
    print("-"*(13+2+6+2+6+2+21+2+15))
    for mjd in mjdList:
        # Set the date and compute the location of the target
        obs.date = mjd + astro.MJD_OFFSET - astro.DJD_OFFSET
        bdy.compute(obs)
        az = bdy.az*180/numpy.pi
        el = bdy.alt*180/numpy.pi
        
        if el > 0:
            # Get the latitude, longitude, and height of the ionospheric pierce 
            # point in this direction
            ippLat, ippLon, ippElv = ionosphere.get_ionospheric_pierce_point(site, az, el)
            
            # Load in the TEC value and the RMS from the IGS final data product
            tec, rms = ionosphere.get_tec_value(mjd, lat=ippLat, lng=ippLon, include_rms=True, type=mtype)
            tec, rms = tec[0][0], rms[0][0]
            
            # Use the IGRF to compute the ECEF components of the Earth's magnetic field
            Bx, By, Bz = ionosphere.get_magnetic_field(ippLat, ippLon, ippElv, mjd=mjd, ecef=True)
            
            # Rotate the ECEF field into topocentric coordinates so that we can 
            # get the magnetic field along the line of sight
            rot = numpy.array([[ numpy.sin(site.lat)*numpy.cos(site.long), numpy.sin(site.lat)*numpy.sin(site.long), -numpy.cos(site.lat)], 
                               [-numpy.sin(site.long),                     numpy.cos(site.long),                      0                  ],
                               [ numpy.cos(site.lat)*numpy.cos(site.long), numpy.cos(site.lat)*numpy.sin(site.long),  numpy.sin(site.lat)]])
            ## ECEF -> SEZ
            sez = numpy.dot(rot, numpy.array([Bx, By, Bz]))
            ## SEZ -> NEZ
            enz = 1.0*sez[[1,0,2]]
            enz[1] *= -1.0
            
            # Compute the pointing vector for this direction and use that to get
            # B parallel.  Note that we need a negative sign when we dot to get
            # the direction of propagation right.
            pnt = numpy.array([numpy.cos(el*numpy.pi/180)*numpy.sin(az*numpy.pi/180),
                        numpy.cos(el*numpy.pi/180)*numpy.cos(az*numpy.pi/180), 
                        numpy.sin(el*numpy.pi/180)])
            Bparallel = -numpy.dot(pnt, enz)
            
            # Compute the dispersion measure and the RMS
            DM    = 3.24078e-23 * (tec*1e16)
            rmsDM = 3.24078e-23 * (rms*1e16)
            
            # Compute the rotation measure and the RMS
            RM    = 2.62e-13 * (tec*1e16) * (Bparallel*1e-9)
            rmsRM = 2.62e-13 * (rms*1e16) * (Bparallel*1e-9)
            
            # Report
            print("%013.6f  %6.2f  %6.2f  %8.6f +/- %8.6f  %5.3f +/- %5.3f" % (mjd, az, el, DM, rmsDM, RM, rmsRM))
        else:
            # Write out dummy values since the source isn't up
            print("%013.6f  %6.2f  %6.2f  %8s +/- %8s  %5s +/- %5s" % (mjd, az, el, '---', '---', '---', '---'))
Example #6
0
def main(args):
    obs = lwa1.get_observer()
    MST = pytz.timezone('US/Mountain')
    UTC = pytz.utc

    if args.date is None or args.time is None:
        dt = datetime.datetime.utcnow()
        dt = UTC.localize(dt)
    else:
        year, month, day = args.date.split('/', 2)
        hour, minute, second = args.time.split(':', 2)
        iSeconds = int(float(second))
        mSeconds = int(round((float(second) - iSeconds) * 1000000))

        if args.utc:
            # UTC
            dt = UTC.localize(
                datetime.datetime(int(year), int(month), int(day), int(hour),
                                  int(minute), iSeconds, mSeconds))

        elif args.sidereal:
            # LST
            dt = astroDate(int(year), int(month), int(day), 0, 0, 0)
            jd = dt.to_jd()

            ## Get the LST in hours
            LST = int(hour) + int(minute) / 60.0 + (iSeconds +
                                                    mSeconds / 1e6) / 3600.0

            ## Get the Greenwich apparent ST for LST using the longitude of
            ## the site.  The site longitude is stored as radians, so convert
            ## to hours first.
            GAST = LST - obs.long * 12 / math.pi

            ## Get the Greenwich mean ST by removing the equation of the
            ## equinoxes (or some approximation thereof)
            GMST = GAST - _getEquinoxEquation(jd)

            ## Get the value of D0, days since January 1, 2000 @ 12:00 UT,
            ## and T, the number of centuries since the year 2000.  The value
            ## of T isn't terribly important but it is nice to include
            D0 = jd - 2451545.0
            T = D0 / 36525.0

            ## Solve for the UT hour for this LST and map onto 0 -> 24 hours
            ## From: http://aa.usno.navy.mil/faq/docs/GAST.php
            H = GMST - 6.697374558 - 0.06570982441908 * D0 - 0.000026 * T**2
            H /= 1.002737909350795
            while H < 0:
                H += 24 / 1.002737909350795
            while H > 24:
                H -= 24 / 1.002737909350795

            ## Get the full Julian Day that this corresponds to
            jd += H / 24.0

            ## Convert the JD back to a time and extract the relevant
            ## quantities needed to build a datetime instance
            dt = astroGetDate(jd)
            year = dt.years
            month = dt.months
            day = dt.days
            hour = dt.hours
            minute = dt.minutes
            second = int(dt.seconds)
            microsecond = int((dt.seconds - second) * 1e6)
            ## Trim the microsecond down to the millisecond level
            microsecond = int(int(microsecond / 1000.0) * 1000)

            ## Localize as the appropriate time zone
            dt = UTC.localize(
                datetime.datetime(year, month, day, hour, minute, second,
                                  microsecond))

        else:
            # Mountain time
            dt = MST.localize(
                datetime.datetime(int(year), int(month), int(day), int(hour),
                                  int(minute), iSeconds, mSeconds))

        dt = dt.astimezone(UTC)

    obs.date = dt.astimezone(UTC).strftime("%Y/%m/%d %H:%M:%S.%f")
    mjd, mpm = datetime_to_mjdmpm(dt)

    print("Localtime: %s" %
          dt.astimezone(MST).strftime("%B %d, %Y at %H:%M:%S %Z"))
    print("UTC: %s" % dt.astimezone(UTC).strftime("%B %d, %Y at %H:%M:%S %Z"))
    print("LST: %s" % obs.sidereal_time())
    print("MJD: %i" % mjd)
    print("MPM: %i" % mpm)
def main(args):
    # Parse the command line
    config = parseOptions(args)

    # Get LWA-1
    observer = lwa1.get_observer()
    print("Current site is %s at lat %s, lon %s" %
          (lwa1.name, observer.lat, observer.long))

    # Set the current time so we can find the "next" transit.  Go ahead
    # and report the time and the current LST (for reference)
    if len(config['args']) == 1:
        config['args'][0] = config['args'][0].replace('-', '/')
        year, month, day = config['args'][0].split('/', 2)
        year = int(year)
        month = int(month)
        day = int(day)
        tNow = _UTC.localize(datetime(year, month, day))

    else:
        tNow = _UTC.localize(datetime.utcnow())
    observer.date = tNow.strftime("%Y/%m/%d %H:%M:%S")
    print("Current time is %s" %
          tNow.astimezone(_UTC).strftime("%Y/%m/%d %H:%M:%S %Z"))
    print("Current LST at %s is %s" % (lwa1.name, observer.sidereal_time()))

    # Load in the sources and compute
    srcs = [ephem.Sun(), ephem.Jupiter()]
    for line in _srcs:
        srcs.append(ephem.readdb(line))
    for i in xrange(len(srcs)):
        srcs[i].compute(observer)

    #
    # Standard prediction output
    #

    # Header
    print("")
    print("%-10s  %-23s" % (
        "Source",
        "Next Transit",
    ))
    print("=" * (10 + 2 + 23))

    # List
    found = False
    for src in srcs:
        if src.name.lower() == config['source'].lower():
            found = True

            nT = str(
                observer.next_transit(
                    src, start=tNow.strftime("%Y/%m/%d %H:%M:%S")))
            nT = _UTC.localize(datetime.strptime(nT, "%Y/%m/%d %H:%M:%S"))

            print("%-10s %-23s" %
                  (src.name, nT.strftime("%Y/%m/%d %H:%M:%S %Z")))
            print("%-10s %-23s" %
                  ("", nT.astimezone(_MST).strftime("%Y/%m/%d %H:%M:%S %Z")))
            print(" ")
            break

    if found:
        startRec = nT - timedelta(seconds=int(round(config['duration'] / 2.0)))
        mjd, mpm = datetime_to_mjdmpm(startRec)
        dur = int(round(config['duration'] * 1000))
        cmd = 'DR5 REC "%i %i %i TBN_FILT_%i"' % (mjd, mpm, dur,
                                                  config['filter'])

        antpols = 520
        sample_rate = tbn_filters[config['filter']]
        dataRate = 1.0 * sample_rate / 512 * tbnFRAME_SIZE * antpols

        print("Recording:")
        print(" Start: %s" % startRec.strftime("%Y/%m/%d %H:%M:%S %Z"))
        print("        %s" %
              startRec.astimezone(_MST).strftime("%Y/%m/%d %H:%M:%S %Z"))
        print(" Duration: %.3f s" % (dur / 1000.0, ))
        print(" TBN Filter Code: %i" % config['filter'])
        print(" Data rate: %.2f MB/s" % (dataRate / 1024**2, ))
        print(" Data volume: %.2f GB" % (dataRate * dur / 1000.0 / 1024**3, ))
        print(" ")

        print("Data Recorder Command:")
        print(" %s" % cmd)
    else:
        raise RuntimeError("Unknown source '%s'" % config['source'])
Example #8
0
def _parse_tec_map(filename_or_fh):
    """
    Given the name of a file containing a TEC map from the IGC, parse it 
    and return a dictionary containing the files data.
    
    The dictionary keys are:
     * dates - array of MJD values for each time step in the map
     * lats - 2-D array of latitude values for the maps in degrees
     * lngs - 2-D array of longitude values for the maps in degrees
     * height - height for the ionospheric pierce point in km
     * tec - 3-D array of TEC values in TECU.  The dimensions are time by
             latitude by longitude.
     * rms - 3-D array of TEC RMS values in TECU.  The dimensions are time
             by latitude by longitude.
    """

    # Variables to hold the map sequences
    dates = []
    tecMaps = []
    rmsMaps = []

    # State control variables to help keep up with where we are
    inMap = False
    inBlock = False

    try:
        fh = gzip.GzipFile(filename_or_fh, 'rb')
    except TypeError:
        fh = gzip.GzipFile(fileobj=filename_or_fh, mode='rb')

    try:
        for line in fh:
            try:
                line = line.decode('ascii', errors='ignore')
            except AttributeError:
                pass

            ## Are we beginning a map?
            line = line.replace('\n', '')
            if line.find('START OF TEC MAP') != -1 or line.find(
                    'START OF RMS MAP') != -1:
                inMap = True
                continue

            ## Have we just ended a map?
            if line.find('END OF TEC MAP') != -1 or line.find(
                    'END OF RMS MAP') != -1:
                if line.find('TEC') != -1:
                    tecMaps.append(cmap)
                else:
                    rmsMaps.append(cmap)

                inMap = False
                continue

            ## Are we in a map?
            if inMap:
                ## Is this part of the preamble?
                if line.find('EPOCH OF CURRENT MAP') != -1:
                    ### Parse the date/time string
                    year, month, day, hour, minute, second = line.split(
                        None, 6)[:6]
                    year = int(year)
                    month = int(month)
                    day = int(day)
                    hour = int(hour)
                    minute = int(minute)
                    second = int(second)

                    ### Figure out the MJD
                    try:
                        dt = datetime(year, month, day, hour, minute, second,
                                      0)
                    except ValueError:
                        if hour >= 24:
                            dt = datetime(year, month, day, hour - 24, minute,
                                          second, 0)
                            dt += timedelta(days=1)
                        else:
                            continue
                    mjd, mpm = datetime_to_mjdmpm(dt)
                    mjd = mjd + mpm / 1000.0 / 3600.0 / 24.0
                    if mjd not in dates:
                        dates.append(mjd)

                    ### Initialize the map and the coorindates
                    cmap = []
                    lats = []
                    lngs = []

                    continue

                ## Is this a different part of the preamble?
                elif line.find('LAT/LON1/LON2/DLON/H') != -1:
                    lat = float(line[3:8])
                    lng1 = float(line[8:14])
                    lng2 = float(line[14:20])
                    dlng = float(line[20:26])
                    height = float(line[26:32])

                    cmap.append([])
                    lats.append(lat)
                    lngs = list(numpy.arange(lng1, lng2 + dlng, dlng))

                    inBlock = True
                    continue

                ## Process the data block keeping in mind that missing values are stored
                ## as 9999
                if inBlock:
                    fields = numpy.array(
                        [float(v) / 10.0 for v in line.split(None)])
                    fields[numpy.where(fields == 999.9)] = numpy.nan

                    cmap[-1].extend(fields)
                    continue

    finally:
        fh.close()

    # Combine everything together
    dates = numpy.array(dates, dtype=numpy.float64)
    tec = numpy.array(tecMaps, dtype=numpy.float32)
    rms = numpy.array(rmsMaps, dtype=numpy.float32)
    lats = numpy.array(lats, dtype=numpy.float32)
    lngs = numpy.array(lngs, dtype=numpy.float32)

    # Do we have a valid RMS map?  If not, make one.
    if rms.size != tec.size:
        rms = tec * 0.05

    # Make lats and lngs 2-D to match the data
    lngs, lats = numpy.meshgrid(lngs, lats)

    # Build up the output
    output = {
        'dates': dates,
        'lats': lats,
        'lngs': lngs,
        'height': height,
        'tec': tec,
        'rms': rms
    }

    # Done
    return output
Example #9
0
def get_magnetic_field(lat, lng, elev, mjd=None, ecef=False):
    """
    Given a geodetic location described by a latitude in degrees (North 
    positive), a longitude in degrees (West negative), an elevation 
    in meters and an MJD value, compute the Earth's magnetic field in that 
    location and return a three-element tuple of the magnetic field's 
    components in nT.  By default these are in topocentric coordinates of
    (North, East, Up).  To return values in ECEF, set the 'ecef' keyword to
    True.  If the MJD file is None, the current time is used.
    
    .. note::
        The convention used for the topocentric coordinates differs
        from what the IGRF uses in the sense that the zenith direction
        points up rather than down.
    """

    # Get the current time if mjd is None
    if mjd is None:
        mjd, mpm = datetime_to_mjdmpm(datetime.utcnow())
        mjd = mjd + mpm / 1000.0 / 3600.0 / 24.0

    # Convert the MJD to a decimal year.  This is a bit tricky
    ## Break the MJD into an integer MJD and an MPM in order to build a datetime instance
    mpm = int((mjd - int(mjd)) * 24.0 * 3600.0 * 1000.0)
    mjd0 = mjdmpm_to_datetime(int(mjd), mpm)
    ## Convert the datetime instance to January 1
    mjd0 = mjd0.replace(month=1, day=1, hour=0, second=0, microsecond=0)
    ## Figure out January 1 for the following year
    mjd1 = mjd0.replace(year=mjd0.year + 1)
    ## Figure out how long the year is in days
    diffDays = mjd1 - mjd0
    diffDays = diffDays.days + diffDays.seconds / 86400.0 + diffDays.microseconds / 1e6 / 86400.0
    ## Convert the January 1 date back to an MJD
    mjd0, mpm0 = datetime_to_mjdmpm(mjd0)
    mjd0 = mjd0 + mpm / 1000.0 / 3600.0 / 24.0
    year = (mjd1.year - 1) + (mjd - mjd0) / diffDays

    # Convert the geodetic position provided to a geocentric one for calculation
    ## Deal with the poles
    if 90.0 - lat < 0.001:
        xyz = numpy.array(
            geo_to_ecef(89.999 * numpy.pi / 180, lng * numpy.pi / 180, elev))
    elif 90.0 + lat < 0.001:
        xyz = numpy.array(
            geo_to_ecef(-89.999 * numpy.pi / 180, lng * numpy.pi / 180, elev))
    else:
        xyz = numpy.array(
            geo_to_ecef(lat * numpy.pi / 180, lng * numpy.pi / 180, elev))
    ## To geocentric
    r = numpy.sqrt((xyz**2).sum())
    lt = numpy.arcsin(xyz[2] / r)
    ln = numpy.arctan2(xyz[1], xyz[0])

    # Load in the coefficients
    try:
        coeffs = _ONLINE_CACHE['IGRF']
    except KeyError:
        filename = os.path.join(dataPath, 'igrf13coeffs.txt')
        _ONLINE_CACHE['IGRF'] = _load_igrf(filename)

        coeffs = _ONLINE_CACHE['IGRF']

    # Compute the coefficients for the epoch
    coeffs = _compute_igrf_coefficents(year, coeffs)

    # Compute the field strength in spherical coordinates
    Br, Bth, Bph = 0.0, 0.0, 0.0
    for n in coeffs['g'].keys():
        for m in range(0, n + 1):
            Br += (n + 1.0) * (_RADIUS_EARTH / r)**(n + 2) * _Snm(
                n, m) * coeffs['g'][n][m] * numpy.cos(m * ln) * _Pnm(
                    n, m, numpy.sin(lt))
            Br += (n + 1.0) * (_RADIUS_EARTH / r)**(n + 2) * _Snm(
                n, m) * coeffs['h'][n][m] * numpy.sin(m * ln) * _Pnm(
                    n, m, numpy.sin(lt))

            Bth -= (_RADIUS_EARTH / r)**(n + 2) * _Snm(
                n, m) * coeffs['g'][n][m] * numpy.cos(m * ln) * _dPnm(
                    n, m, numpy.sin(lt))
            Bth -= (_RADIUS_EARTH / r)**(n + 2) * _Snm(
                n, m) * coeffs['h'][n][m] * numpy.sin(m * ln) * _dPnm(
                    n, m, numpy.sin(lt))

            Bph += (_RADIUS_EARTH / r)**(n + 2) / numpy.cos(lt) * _Snm(
                n, m) * coeffs['g'][n][m] * m * numpy.sin(m * ln) * _Pnm(
                    n, m, numpy.sin(lt))
            Bph -= (_RADIUS_EARTH / r)**(n + 2) / numpy.cos(lt) * _Snm(
                n, m) * coeffs['h'][n][m] * m * numpy.cos(m * ln) * _Pnm(
                    n, m, numpy.sin(lt))
    ## And deal with NaNs
    if numpy.isnan(Br):
        Br = 0.0
    if numpy.isnan(Bth):
        Bth = 0.0
    if numpy.isnan(Bph):
        Bph = 0.0

    # Convert from spherical to ECEF
    Bx = Br * numpy.cos(lt) * numpy.cos(ln) + Bth * numpy.sin(lt) * numpy.cos(
        ln) - Bph * numpy.sin(ln)
    By = Br * numpy.cos(lt) * numpy.sin(ln) + Bth * numpy.sin(lt) * numpy.sin(
        ln) + Bph * numpy.cos(ln)
    Bz = Br * numpy.sin(lt) - Bth * numpy.cos(lt)

    # Are we done?
    if ecef:
        # For ECEF we don't need to do anything else
        outputField = Bx, By, Bz

    else:
        # Convert from ECEF to topocentric (geodetic)
        ## Update the coordinates for geodetic
        lt = lat * numpy.pi / 180.0
        if 90.0 - lat < 0.001:
            lt = 89.999 * numpy.pi / 180.0
        elif 90.0 + lat < 0.001:
            lt = -89.999 * numpy.pi / 180.0
        else:
            lt = lat * numpy.pi / 180.0
        ln = lng * numpy.pi / 180.0

        ## Build the rotation matrix for ECEF to SEZ
        rot = numpy.array([[
            numpy.sin(lt) * numpy.cos(ln),
            numpy.sin(lt) * numpy.sin(ln), -numpy.cos(lt)
        ], [-numpy.sin(ln), numpy.cos(ln), 0],
                           [
                               numpy.cos(lt) * numpy.cos(ln),
                               numpy.cos(lt) * numpy.sin(ln),
                               numpy.sin(lt)
                           ]])

        ## Apply and extract
        sez = numpy.dot(rot, numpy.array([Bx, By, Bz]))
        Bn, Be, Bz = -sez[0], sez[1], sez[2]

        outputField = Bn, Be, Bz

    # Done
    return outputField
Example #10
0
def _parse_ustec_map(filename_or_fh):
    """
    Given the name of a file containing a TEC map from the USTEC project, 
    parse it and return a dictionary containing the files data.
    
    The dictionary keys are:
     * dates - array of MJD values for each time step in the map
     * lats - 2-D array of latitude values for the maps in degrees
     * lngs - 2-D array of longitude values for the maps in degrees
     * height - height for the ionospheric pierce point in km
     * tec - 3-D array of TEC values in TECU.  The dimensions are time by
        latitude by longitude.
     * rms - 3-D array of TEC RMS values in TECU.  The dimensions are time
        by latitude by longitude.
    """

    try:
        tf = tarfile.open(filename_or_fh, 'r:*')
        do_close = True
    except TypeError:
        tf = tarfile.open(fileobj=filename_or_fh, mode='r:*')
        do_close = False

    valid_filename = lambda x: ((x.find('_TEC.txt') != -1) \
                                or (x.find('_ERR.txt') != -1) \
                                or (x.find('_EOF.txt') != -1))
    try:
        tecFiles = {}
        errFiles = {}
        eofFiles = {}
        for entry in tf:
            if not valid_filename(entry.name):
                continue

            contents = tf.extractfile(entry.name).read()
            try:
                contents = contents.decode()
            except AttributeError:
                # Python2 catch
                pass
            contents = StringIO(contents)

            if entry.name.find('_TEC.txt') != -1:
                tecFiles[entry.name] = contents
            elif entry.name.find('_ERR.txt') != -1:
                errFiles[entry.name] = contents
            elif entry.name.find('_EOF.txt') != -1:
                eofFiles[entry.name] = contents

        # Variables to hold the map sequences
        dates = []
        tecMaps = []
        rmsMaps = []

        # Get all of the TEC map files and load them in
        tecfilenames = list(tecFiles.keys())
        tecfilenames.sort()
        for tecfilename in tecfilenames:
            tecfh = tecFiles[tecfilename]
            try:
                rmsfilename = tecfilename.replace('_TEC', '_ERR')
                rmsfh = errFiles[rmsfilename]
            except KeyError:
                rmsfh = None
            lats, lngs, tec, rms = _parse_ustec_individual(tecfh,
                                                           rmsname_or_fh=rmsfh)

            ### Figure out the MJD
            dt = os.path.basename(tecfilename).split('_')[0]
            dt = datetime.strptime(dt, "%Y%m%d%H%M")
            mjd, mpm = datetime_to_mjdmpm(dt)
            mjd = mjd + mpm / 1000.0 / 3600.0 / 24.0
            if mjd not in dates:
                dates.append(mjd)

            # Stack on the new TEC and RMS maps
            tecMaps.append(tec)
            rmsMaps.append(rms)

            #except Exception as e:
            #pass

        # Get the mean ionospheric height
        eoffilename = list(eofFiles.keys())[0]
        #try:
        height = _parse_ustec_height(eofFiles[eoffilename])
        #except:
        #	height = 450

    finally:
        if do_close:
            tf.close()

    # Combine everything together
    dates = numpy.array(dates, dtype=numpy.float64)
    tec = numpy.array(tecMaps, dtype=numpy.float32)
    rms = numpy.array(rmsMaps, dtype=numpy.float32)

    # Build up the output
    output = {
        'dates': dates,
        'lats': lats,
        'lngs': lngs,
        'height': height,
        'tec': tec,
        'rms': rms
    }

    # Done
    return output
Example #11
0
    def time(self):
        """
        Function to convert the time tag to seconds since the UNIX epoch as a 
        `lsl.reader.base.FrameTimestamp` instance.
        """

        # Get the reference epoch in the strange way that it is stored in VDIF
        # and convert it to a MJD
        epochDT = datetime(2000 + self.ref_epoch // 2,
                           (self.ref_epoch % 2) * 6 + 1, 1, 0, 0, 0, 0)
        epochMJD, epochMPM = datetime_to_mjdmpm(epochDT)
        epochMJD = epochMJD + epochMPM / 1000.0 / 86400.0

        # Get the frame MJD by adding the seconds_from_epoch value to the epoch
        frameMJD_i = epochMJD + self.seconds_from_epoch // 86400
        frameMJD_f = (self.seconds_from_epoch % 86400) / 86400.0
        frameMJD_s = 0.0

        if self.sample_rate == 0.0:
            # Try to get the sub-second time by parsing the extended user data
            try:
                ## Is there a sample rate to grab?
                eud = self.extended_user_data
                sample_rate = eud['sample_rate']
                sample_rate *= 1e6 if eud['sample_rate_units'] == 'MHz' else 1e3

                ## How many samples are in each frame?
                dataSize = self.frame_length * 8 - 32 + 16 * self.is_legacy  # 8-byte chunks -> bytes - full header + legacy offset
                samplesPerWord = 32 // self.bits_per_sample  # dimensionless
                nSamples = dataSize // 4 * samplesPerWord  # bytes -> words -> data samples
                nSamples = nSamples / self.nchan / (
                    2 if self.is_complex else 1
                )  # data samples -> time samples

                ## What is the frame rate?
                frameRate = sample_rate // nSamples

                frameMJD_s += 1.0 * self.frame_in_second / frameRate

            except KeyError:
                warnings.warn(
                    colorfy(
                        "{{%yellow Insufficient information to determine exact frame timestamp, time will be approximate"
                    ), RuntimeWarning)

        else:
            # Use what we already have been told
            ## How many samples are in each frame?
            dataSize = self.frame_length * 8 - 32 + 16 * self.is_legacy  # 8-byte chunks -> bytes - full header + legacy offset
            samplesPerWord = 32 // self.bits_per_sample  # dimensionless
            nSamples = dataSize // 4 * samplesPerWord  # bytes -> words -> samples
            nSamples = nSamples // self.nchan // (
                2 if self.is_complex else 1)  # data samples -> time samples

            ## What is the frame rate?
            frameRate = self.sample_rate // nSamples

            frameMJD_s += 1.0 * self.frame_in_second / frameRate

        # Convert from MJD to UNIX time
        if frameMJD_f > 1:
            frameMJD_i += 1
            frameMJD_f -= 1

        return FrameTimestamp.from_pulsar_mjd(frameMJD_i, frameMJD_f,
                                              frameMJD_s)
Example #12
0
def _parse_ustec_map(filename):
    """
    Given the name of a file containing a TEC map from the USTEC project, 
    parse it and return a dictionary containing the files data.
    
    The dictionary keys are:
     * dates - array of MJD values for each time step in the map
     * lats - 2-D array of latitude values for the maps in degrees
     * lngs - 2-D array of longitude values for the maps in degrees
     * height - height for the ionospheric pierce point in km
     * tec - 3-D array of TEC values in TECU.  The dimensions are time by
        latitude by longitude.
     * rms - 3-D array of TEC RMS values in TECU.  The dimensions are time
        by latitude by longitude.
    """

    tempDir = tempfile.mkdtemp(prefix='ionosphere-')

    tf = tarfile.open(filename, 'r:*')
    tecFiles = [
        tio for tio in tf.getmembers() if tio.name.find('_TEC.txt') != -1
    ]
    errFiles = [
        tio for tio in tf.getmembers() if tio.name.find('_ERR.txt') != -1
    ]
    eofFiles = [
        tio for tio in tf.getmembers() if tio.name.find('_EOF.txt') != -1
    ]
    tf.extractall(path=tempDir, members=tecFiles)
    tf.extractall(path=tempDir, members=errFiles)
    tf.extractall(path=tempDir, members=eofFiles)

    # Variables to hold the map sequences
    dates = []
    tecMaps = []
    rmsMaps = []

    # Get all of the TEC map files and load them in
    tecfilenames = glob.glob(os.path.join(tempDir, '*_TEC.txt'))
    tecfilenames.sort()
    for tecfilename in tecfilenames:
        #try:
        dt, lats, lngs, tec, rms = _parse_ustec_individual(tecfilename)

        ### Figure out the MJD
        mjd, mpm = datetime_to_mjdmpm(dt)
        mjd = mjd + mpm / 1000.0 / 3600.0 / 24.0
        if mjd not in dates:
            dates.append(mjd)

        # Stack on the new TEC and RMS maps
        tecMaps.append(tec)
        rmsMaps.append(rms)

        #except Exception as e:
        #pass

    # Get the mean ionospheric height
    eoffilename = glob.glob(os.path.join(tempDir, '*_EOF.txt'))[0]
    #try:
    height = _parse_ustec_height(eoffilename)
    #except:
    #	height = 450

    # Cleanup
    tf.close()
    shutil.rmtree(tempDir, ignore_errors=True)

    # Combine everything together
    dates = numpy.array(dates, dtype=numpy.float64)
    tec = numpy.array(tecMaps, dtype=numpy.float32)
    rms = numpy.array(rmsMaps, dtype=numpy.float32)

    # Build up the output
    output = {
        'dates': dates,
        'lats': lats,
        'lngs': lngs,
        'height': height,
        'tec': tec,
        'rms': rms
    }

    # Done
    return output