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
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