Example #1
0
def add_hwm_winds_and_ecef_vectors(inst,
                                   glat_label='glat',
                                   glong_label='glong',
                                   alt_label='alt'):
    """ 
    Uses HWM (Horizontal Wind Model) model to obtain neutral wind details.
    
    Uses pyglow module to run HWM. Configured to use actual solar parameters to run 
    model.
    
    Example
    -------
        # function added velow modifies the inst object upon every inst.load call
        inst.custom.add(add_hwm_winds_and_ecef_vectors, 'modify', glat_label='custom_label')
    
    Parameters
    ----------
    inst : pysat.Instrument
        Designed with pysat_sgp4 in mind
    glat_label : string
        label used in inst to identify WGS84 geodetic latitude (degrees)
    glong_label : string
        label used in inst to identify WGS84 geodetic longitude (degrees)
    alt_label : string
        label used in inst to identify WGS84 geodetic altitude (km, height above surface)
        
    Returns
    -------
    inst
        Input pysat.Instrument object modified to include HWM winds.
        'zonal_wind' for the east/west winds (u in model) in m/s
        'meiridional_wind' for the north/south winds (v in model) in m/s
        'unit_zonal_wind_ecef_*' (*=x,y,z) is the zonal vector expressed in the ECEF basis
        'unit_mer_wind_ecef_*' (*=x,y,z) is the meridional vector expressed in the ECEF basis
        'sim_inst_wind_*' (*=x,y,z) is the projection of the total wind vector onto s/c basis
        
    """

    import pyglow
    import pysatMagVect

    hwm_params = []
    for time, lat, lon, alt in zip(inst.data.index, inst[glat_label],
                                   inst[glong_label], inst[alt_label]):
        # Point class is instantiated.
        # Its parameters are a function of time and spatial location
        pt = pyglow.Point(time, lat, lon, alt)
        pt.run_hwm()
        hwm = {}
        hwm['zonal_wind'] = pt.u
        hwm['meridional_wind'] = pt.v
        hwm_params.append(hwm)
    # print 'Complete.'
    hwm = pds.DataFrame(hwm_params)
    hwm.index = inst.data.index
    inst[['zonal_wind',
          'meridional_wind']] = hwm[['zonal_wind', 'meridional_wind']]

    # calculate zonal unit vector in ECEF
    # zonal wind: east - west; positive east
    # EW direction is tangent to XY location of S/C in ECEF coordinates
    mag = np.sqrt(inst['position_ecef_x']**2 + inst['position_ecef_y']**2)
    inst['unit_zonal_wind_ecef_x'] = -inst['position_ecef_y'] / mag
    inst['unit_zonal_wind_ecef_y'] = inst['position_ecef_x'] / mag
    inst['unit_zonal_wind_ecef_z'] = 0 * inst['position_ecef_x']

    # calculate meridional unit vector in ECEF
    # meridional wind: north - south; positive north
    # mer direction completes RHS of position and zonal vector
    unit_pos_x, unit_pos_y, unit_pos_z = \
        pysatMagVect.normalize_vector(-inst['position_ecef_x'], -inst['position_ecef_y'], -inst['position_ecef_z'])

    # mer = r x zonal
    inst['unit_mer_wind_ecef_x'], inst['unit_mer_wind_ecef_y'], inst['unit_mer_wind_ecef_z'] = \
        pysatMagVect.cross_product(unit_pos_x, unit_pos_y, unit_pos_z,
                                   inst['unit_zonal_wind_ecef_x'], inst['unit_zonal_wind_ecef_y'], inst['unit_zonal_wind_ecef_z'])

    # Adding metadata information
    inst.meta['zonal_wind'] = {
        'units': 'm/s',
        'long_name': 'Zonal Wind',
        'desc': 'HWM model zonal wind'
    }
    inst.meta['meridional_wind'] = {
        'units': 'm/s',
        'long_name': 'Meridional Wind',
        'desc': 'HWM model meridional wind'
    }
    inst.meta['unit_zonal_wind_ecef_x'] = {
        'units': '',
        'long_name': 'Zonal Wind Unit ECEF x-vector',
        'desc': 'x-value of zonal wind unit vector in ECEF co ordinates'
    }
    inst.meta['unit_zonal_wind_ecef_y'] = {
        'units': '',
        'long_name': 'Zonal Wind Unit ECEF y-vector',
        'desc': 'y-value of zonal wind unit vector in ECEF co ordinates'
    }
    inst.meta['unit_zonal_wind_ecef_z'] = {
        'units': '',
        'long_name': 'Zonal Wind Unit ECEF z-vector',
        'desc': 'z-value of zonal wind unit vector in ECEF co ordinates'
    }
    inst.meta['unit_mer_wind_ecef_x'] = {
        'units': '',
        'long_name': 'Meridional Wind Unit ECEF x-vector',
        'desc': 'x-value of meridional wind unit vector in ECEF co ordinates'
    }
    inst.meta['unit_mer_wind_ecef_y'] = {
        'units': '',
        'long_name': 'Meridional Wind Unit ECEF y-vector',
        'desc': 'y-value of meridional wind unit vector in ECEF co ordinates'
    }
    inst.meta['unit_mer_wind_ecef_z'] = {
        'units': '',
        'long_name': 'Meridional Wind Unit ECEF z-vector',
        'desc': 'z-value of meridional wind unit vector in ECEF co ordinates'
    }
    return
Example #2
0
def add_sc_attitude_vectors(inst):
    """
    Add attitude vectors for spacecraft assuming ram pointing. 
     
    Presumes spacecraft is pointed along the velocity vector (x), z is
    generally nadir pointing (positive towards Earth), and y completes the 
    right handed system (generally southward).
    
    Notes
    -----
        Expects velocity and position of spacecraft in Earth Centered
        Earth Fixed (ECEF) coordinates to be in the instrument object
        and named velocity_ecef_* (*=x,y,z) and position_ecef_* (*=x,y,z)
    
        Adds attitude vectors for spacecraft in the ECEF basis by calculating the scalar
        product of each attitude vector with each component of ECEF. 

    Parameters
    ----------
    inst : pysat.Instrument
        Instrument object
        
    Returns
    -------
    None
        Modifies pysat.Instrument object in place to include S/C attitude unit
        vectors, expressed in ECEF basis. Vectors are named sc_(x,y,z)hat_ecef_(x,y,z).
        sc_xhat_ecef_x is the spacecraft unit vector along x (positive along velocity vector)
        reported in ECEF, ECEF x-component.

    """
    import pysatMagVect

    # ram pointing is along velocity vector
    inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'] = \
        pysatMagVect.normalize_vector(inst['velocity_ecef_x'], inst['velocity_ecef_y'], inst['velocity_ecef_z'])

    # begin with z along Nadir (towards Earth)
    # if orbit isn't perfectly circular, then the s/c z vector won't
    # point exactly along nadir. However, nadir pointing is close enough
    # to the true z (in the orbital plane) that we can use it to get y,
    # and use x and y to get the real z
    inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \
        pysatMagVect.normalize_vector(-inst['position_ecef_x'], -inst['position_ecef_y'], -inst['position_ecef_z'])

    # get y vector assuming right hand rule
    # Z x X = Y
    inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \
        pysatMagVect.cross_product(inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'],
                                   inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'])
    # normalize since Xhat and Zhat from above may not be orthogonal
    inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \
        pysatMagVect.normalize_vector(inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'])

    # strictly, need to recalculate Zhat so that it is consistent with RHS
    # just created
    # Z = X x Y
    inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \
        pysatMagVect.cross_product(inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'],
                                   inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'])

    # Adding metadata
    inst.meta['sc_xhat_ecef_x'] = {
        'units':
        '',
        'desc':
        'S/C attitude (x-direction, ram) unit vector, expressed in ECEF basis, x-component'
    }
    inst.meta['sc_xhat_ecef_y'] = {
        'units':
        '',
        'desc':
        'S/C attitude (x-direction, ram) unit vector, expressed in ECEF basis, y-component'
    }
    inst.meta['sc_xhat_ecef_z'] = {
        'units':
        '',
        'desc':
        'S/C attitude (x-direction, ram) unit vector, expressed in ECEF basis, z-component'
    }

    inst.meta['sc_zhat_ecef_x'] = {
        'units':
        '',
        'desc':
        'S/C attitude (z-direction, generally nadir) unit vector, expressed in ECEF basis, x-component'
    }
    inst.meta['sc_zhat_ecef_y'] = {
        'units':
        '',
        'desc':
        'S/C attitude (z-direction, generally nadir) unit vector, expressed in ECEF basis, y-component'
    }
    inst.meta['sc_zhat_ecef_z'] = {
        'units':
        '',
        'desc':
        'S/C attitude (z-direction, generally nadir) unit vector, expressed in ECEF basis, z-component'
    }

    inst.meta['sc_yhat_ecef_x'] = {
        'units':
        '',
        'desc':
        'S/C attitude (y-direction, generally south) unit vector, expressed in ECEF basis, x-component'
    }
    inst.meta['sc_yhat_ecef_y'] = {
        'units':
        '',
        'desc':
        'S/C attitude (y-direction, generally south) unit vector, expressed in ECEF basis, y-component'
    }
    inst.meta['sc_yhat_ecef_z'] = {
        'units':
        '',
        'desc':
        'S/C attitude (y-direction, generally south) unit vector, expressed in ECEF basis, z-component'
    }

    # check what magnitudes we get
    mag = np.sqrt(inst['sc_zhat_ecef_x']**2 + inst['sc_zhat_ecef_y']**2 +
                  inst['sc_zhat_ecef_z']**2)
    idx, = np.where((mag < .999999999) | (mag > 1.000000001))
    if len(idx) > 0:
        print(mag[idx])
        raise RuntimeError(
            'Unit vector generation failure. Not sufficently orthogonal.')

    return