diff --git a/PSPoperations/__pycache__/data_handling.cpython-38.pyc b/PSPoperations/__pycache__/data_handling.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49509b62a75d10286c70b8515c840f6b0aa0494a Binary files /dev/null and b/PSPoperations/__pycache__/data_handling.cpython-38.pyc differ diff --git a/PSPoperations/__pycache__/data_quality.cpython-38.pyc b/PSPoperations/__pycache__/data_quality.cpython-38.pyc index a318e2cbeadf6a52cd370cd7bc005d2f437c39e9..66ad3157df0b1fe28a53a232e9dd6b66ac18abab 100644 Binary files a/PSPoperations/__pycache__/data_quality.cpython-38.pyc and b/PSPoperations/__pycache__/data_quality.cpython-38.pyc differ diff --git a/PSPoperations/__pycache__/data_transformation.cpython-38.pyc b/PSPoperations/__pycache__/data_transformation.cpython-38.pyc index 6fc03a2c8fc606a3e9f7fc3c9073b61f16587210..8991004c53960278dba9ff7e59bf24cb70a95a15 100644 Binary files a/PSPoperations/__pycache__/data_transformation.cpython-38.pyc and b/PSPoperations/__pycache__/data_transformation.cpython-38.pyc differ diff --git a/PSPoperations/__pycache__/plot_settings.cpython-38.pyc b/PSPoperations/__pycache__/plot_settings.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e9945b7d6381f47e2d8e13affba059927fd0854 Binary files /dev/null and b/PSPoperations/__pycache__/plot_settings.cpython-38.pyc differ diff --git a/PSPoperations/data_handling.py b/PSPoperations/data_handling.py new file mode 100644 index 0000000000000000000000000000000000000000..3772ca29c3fe956936c625488ba57f8e30934eb7 --- /dev/null +++ b/PSPoperations/data_handling.py @@ -0,0 +1,73 @@ +import os +import typing as tp +import numpy as np + +# CDF library (is needed to interface with the measurement data files) +# see https://cdf.gsfc.nasa.gov/ +os.environ["CDF_LIB"] = "/usr/local/cdf/lib" + + +def cdf_slice(cdf_file, key: str): + """ + DOC + + :param cdf_file: + :param key: + :return: + """ + return cdf_file[key][...] + + +def data_generation(cdf_file) -> tp.Dict: + """ + DOC + + :param cdf_file: + :return: + """ + data = { + "dqf": cdf_slice(cdf_file, key="general_flag"), + "epoch": cdf_slice(cdf_file, key="Epoch"), + "pos": cdf_slice(cdf_file, key="sc_pos_HCI"), + "vr": cdf_slice(cdf_file, key="vp_moment_RTN")[:, 0], + "dvrhi": cdf_slice(cdf_file, key="vp_moment_RTN_deltahigh")[:, 0], + "dvrlo": cdf_slice(cdf_file, key="vp_moment_RTN_deltalow")[:, 0], + "wp": cdf_slice(cdf_file, key="wp_moment"), + "dwphi": cdf_slice(cdf_file, key="wp_moment_deltahigh"), + "dwplo": cdf_slice(cdf_file, key="wp_moment_deltalow") + } + + return data + + +def array_reduction(data_array: np.ndarray, + index_list: np.ndarray) -> np.ndarray: + """ + Reduction of an array by a list of indices. + + :param data_array: NDARRAY, + Array that is to be reduced + :param index_list: NDARRAY, + List of indices that should be deleted + :return: NDARRAY, + The reduced array + """ + # Choose axis=0 to delete rows and not flatten the array + reduced_array = np.delete(data_array, index_list, axis=0) + + return reduced_array + + +def full_reduction(data_dict: tp.Dict, + bad_indices: np.array) -> tp.Dict: + """ + DOC + + :param data_dict: + :param bad_indices: + :return: + """ + for key in data_dict.keys(): + data_dict[key] = array_reduction(data_dict[key], bad_indices) + + return data_dict diff --git a/PSPoperations/data_quality.py b/PSPoperations/data_quality.py index 416702ba192b9d04aaf31b84ecb11abdbedd7a54..bdb6be47e210f365487e76aa9a3f6cf1522d5806 100644 --- a/PSPoperations/data_quality.py +++ b/PSPoperations/data_quality.py @@ -1,4 +1,5 @@ import numpy as np +import typing as tp def general_flag(general_flag_array: np.ndarray) -> np.ndarray: @@ -22,19 +23,34 @@ def general_flag(general_flag_array: np.ndarray) -> np.ndarray: return index_list -def array_reduction(data_array: np.ndarray, - index_list: np.ndarray) -> np.ndarray: +def meas_failed(meas_array: np.ndarray) -> np.ndarray: """ - Reduction of an array by a list of indices. - - :param data_array: NDARRAY, - Array that is to be reduced - :param index_list: NDARRAY, - List of indices that should be deleted + Takes a 1D array and returns indices of failed measurements (as + indicated by a value of -1e30, SWEAP documentation) + + :param meas_array: NDARRAY, + Measurement array :return: NDARRAY, - The reduced array + Index array """ - # Choose axis=0 to delete rows and not flatten the array - reduced_array = np.delete(data_array, index_list, axis=0) - - return reduced_array + index_array = np.where(meas_array <= -0.5e30)[0] + + return index_array + + +def full_meas_eval(data_dict: tp.Dict): + """DOC""" + col_ind = [] + + for key in data_dict.keys(): + + # Skip unnecessary keys (maybe make this more dynamic?) + if key in ["pos", "dqf", "epoch"]: + continue + + col_ind.append(meas_failed(data_dict[key])) + + # Make an array of unique indices + col_ind = np.unique(np.concatenate(col_ind)) + + return col_ind diff --git a/PSPoperations/data_transformation.py b/PSPoperations/data_transformation.py index 776c806717e0953fb7634ead7962be722b59f21a..a3df0292cb5f080f0d595844cfdfd2644c382d08 100644 --- a/PSPoperations/data_transformation.py +++ b/PSPoperations/data_transformation.py @@ -1,5 +1,7 @@ import numpy as np import typing as tp +# The warnings (for me) here don't seem to matter +from astropy.constants import k_B, m_p def pos_cart_to_sph(position_matrix: np.ndarray) -> tp.Tuple: @@ -28,30 +30,15 @@ def pos_cart_to_sph(position_matrix: np.ndarray) -> tp.Tuple: return r, theta, phi -def vel_cart_to_sph(vel_matrix, r, theta, phi): +def wp_to_temp(thermal_speed: np.ndarray) -> np.ndarray: """ - ??? + Calculate temperature from thermal speed of protons. - :param vel_matrix: - :param r: - :param theta: - :param phi: - :return: + :param thermal_speed: NDARRAY, + Thermal speed (wp) of protons + :return: NDARRAY, + Temperature from wp = sqrt(2k_BT / m) """ - # Sanity checks - assert vel_matrix.shape[1] == 3, \ - "PLEASE CHECK POSITION MATRIX FOR COORDINATE CONVERSION!" - assert r.shape[0] == theta.shape[0] == phi.shape[0] == vel_matrix.shape[0], \ - "PLEASE CHECK DIMENSIONS OF R, THETA, PHI AND VEL_MATRIX!" - - vx = vel_matrix[:, 0] - vy = vel_matrix[:, 1] - vz = vel_matrix[:, 2] - - vr = np.sin(theta) * np.cos(phi) * vx + \ - np.sin(theta) * np.sin(phi) * vy + \ - np.cos(theta) * vz - - return vr + wp_si = thermal_speed * 1e3 - \ No newline at end of file + return wp_si ** 2 * m_p.value / (2 * k_B.value) diff --git a/PSPoperations/plot_settings.py b/PSPoperations/plot_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..8a50ac8149629e0f3a58cfc0687d1861b336adf9 --- /dev/null +++ b/PSPoperations/plot_settings.py @@ -0,0 +1,63 @@ +import matplotlib as mpl +import matplotlib.pyplot as plt + + +def rc_setup(): + """Generalized plot attributes""" + mpl.rcParams["xtick.direction"] = "in" + mpl.rcParams["ytick.direction"] = "in" + mpl.rcParams["xtick.minor.visible"] = "True" + mpl.rcParams["ytick.minor.visible"] = "True" + + +def plot_r_vr(r, vr, v_ulim, v_lolim, save_ind: str = "no"): + """ + Plots radial velocity wrt heliocentric distance + + :param r: NDARRAY, + Distance (must be in km) + :param vr: NDARRAY, + Radial velocity (must be in km/s) + :param v_ulim, v_lolim: NDARRAY, + Upper (lower) uncertainty of vr + :param save_ind: STR, + "yes" if plot should be saved (default: no) + """ + fig, ax = plt.subplots(figsize=(10, 6)) + plt.plot(r / 6.957e5, vr) + plt.fill_between(r / 6.957e5, vr + v_ulim, vr - v_lolim, color="grey", + alpha=0.25) + ax.set( + xlabel="r [R$_\\odot$]", ylabel="v$_r$ [km s$^{-1}$]", + ylim=(0, 800) + ) + ax.grid(True, alpha=0.5) + + if save_ind.lower() == "yes": + plt.savefig("plot_vr.png") + + +def plot_r_temp(r, T, T_ulim, T_lolim, save_ind: str = "no"): + """ + Plots logarithmic temperature wrt heliocentric distance + + :param r: NDARRAY, + Heliocentric distance (mst be in km) + :param T: NDARRAY, + logarithmic Temperature (Kelvin) + :param T_ulim, T_lolim: NDARRAY, + Upper (lower) uncertainty of logT + :param save_ind: STR, + "yes" if plot should be saved (default: no) + """ + fig, ax = plt.subplots(figsize=(10, 6)) + plt.plot(r / 6.957e5, T) + plt.fill_between(r / 6.957e5, T_ulim, T - T_lolim, + color="grey", alpha=0.25) + ax.set( + xlabel="r [R$_\\odot$]", ylabel="T [K]", yscale="log" + ) + ax.grid(True, alpha=0.5) + + if save_ind.lower() == "yes": + plt.savefig("plot_logT.png") diff --git a/TESTING/plot_logT.png b/TESTING/plot_logT.png new file mode 100644 index 0000000000000000000000000000000000000000..a33aca3b4dcee0013851f48a9a29c71eedb6d0f9 Binary files /dev/null and b/TESTING/plot_logT.png differ diff --git a/TESTING/plot_vr.png b/TESTING/plot_vr.png new file mode 100644 index 0000000000000000000000000000000000000000..004d704acaa00458951b0ab61d35407892117aa0 Binary files /dev/null and b/TESTING/plot_vr.png differ diff --git a/TESTING/psp_swp_spc_l3i_20211117_v02.cdf b/TESTING/psp_swp_spc_l3i_20211117_v02.cdf new file mode 100644 index 0000000000000000000000000000000000000000..adb641f3f4584932c96daa492fb563b0579deacc Binary files /dev/null and b/TESTING/psp_swp_spc_l3i_20211117_v02.cdf differ diff --git a/TESTING/testing.py b/TESTING/testing.py new file mode 100644 index 0000000000000000000000000000000000000000..00c593eaee9097d1d4de98808947f6dbfead8129 --- /dev/null +++ b/TESTING/testing.py @@ -0,0 +1,49 @@ +import os +import sys +from unipath import Path +import numpy as np +import matplotlib.pyplot as plt +from spacepy import pycdf + +# Append custom Python modules from parent directory +sys.path.append(Path(sys.path[0]).parent) +from PSPoperations import data_quality as dq +from PSPoperations import data_transformation as dt +from PSPoperations import plot_settings as ps +from PSPoperations import data_handling as dh + + +# Plot set up +ps.rc_setup() + +# CDF library (is needed to interface with the measurement data files) +# see https://cdf.gsfc.nasa.gov/ +os.environ["CDF_LIB"] = "/usr/local/cdf/lib" + +# open CDF file and generate faulty index array +cdf_data = pycdf.CDF("psp_swp_spc_l3i_20211117_v02.cdf") +data = dh.data_generation(cdf_data) + +# Indices of non-usable data from general flag + reduction +bad_ind = dq.general_flag(data["dqf"]) +data = dh.full_reduction(data, bad_ind) + +# Additional reduction from failed measurement indices +mf_ind = dq.full_meas_eval(data) +data = dh.full_reduction(data, mf_ind) + +# Add to data dictionary (spherical coordinates) +data["r"], data["theta"], data["phi"] = dt.pos_cart_to_sph(data["pos"]) + +# Add to data dictionary (temperature) +data["T"] = dt.wp_to_temp(data["wp"]) +data["dThi"] = dt.wp_to_temp(data["dwphi"]) +data["dTlo"] = dt.wp_to_temp(data["dwplo"]) + +# vr plot +ps.plot_r_vr(data["r"], data["vr"], data["dvrhi"], data["dvrlo"], + save_ind="yes") +ps.plot_r_temp(data["r"], data["T"], data["dThi"], data["dTlo"], + save_ind="yes") + +plt.show() diff --git a/main.py b/main.py index 075b2b79b578f7023a4c17e302d3c79813c8bb1e..469a9cf193c86178748f61aa57913b1099e04b15 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,20 @@ +import os +import sys +import matplotlib.pyplot as plt +import numpy as np +from spacepy import pycdf +from PSPoperations import data_quality as dq +from PSPoperations import data_transformation as dt +from PSPoperations import plot_settings as ps + +# Plot parameters +ps.rc_setup() + +# CDF library (is needed to interface with the measurement data files) +# see https://cdf.gsfc.nasa.gov/ +os.environ["CDF_LIB"] = "/usr/local/cdf/lib" + + """ PSEUDOCODE @@ -18,8 +35,71 @@ BACKGROUND OPERATIONS - Sort through "general flag" (only use where set to 0) + -- Also sort through each array to find entries with -1e30, which + marks failed measurements - Calculate spherical heliocentric coordinates (HIC) - Transform to usable data parameters (vr, log_T, log_rho) +- Generate log-file with important information + -- Total number of data points + -- Reduced number of data points + -- Epoch from start to finish """ +ENCOUNTER_NUM = "encounter_5" +DATA_LOCATION = sys.path[0]+"/DATA/"+ENCOUNTER_NUM + +# SANITY CHECK IF DATA LOCATION EXISTS +if not os.path.isdir(DATA_LOCATION): + print(f"\n{DATA_LOCATION} IS NOT A VALID DIRECTORY!\n") + sys.exit(0) + + +def main(): + # Total array setup + r = theta = phi = np.array([]) + vr = dvhi = dvlo = np.array([]) + + for file in os.listdir(DATA_LOCATION): + cdf_data = pycdf.CDF(DATA_LOCATION+"/"+file) + + dqf = cdf_data["general_flag"][...] + bad_ind = dq.general_flag(dqf) + + # generate reduced epoch array + time_file = dq.array_reduction(cdf_data["Epoch"][...], bad_ind) + + # Position + pos_file = dq.array_reduction(cdf_data["sc_pos_HCI"][...], bad_ind) + r_file, theta_file, phi_file = dt.pos_cart_to_sph(pos_file) + + # Velocity + vr_file = dq.array_reduction( + cdf_data["vp_moment_RTN"][...][:, 0], + bad_ind) + dvhi_file = dq.array_reduction( + cdf_data["vp_moment_RTN_deltalow"][...][:, 0], + bad_ind) + dvlo_file = dq.array_reduction( + cdf_data["vp_moment_RTN_deltahigh"][...][:, 0], + bad_ind) + + # Update total arrays + r = np.append(r, r_file) + vr = np.append(vr, vr_file) + + plt.figure() + plt.plot(r, vr) + plt.ylim(0, 1000) + + plt.show() + + +def plot_setup(): + fig_vr, ax_vr = plt.subplots() + ax_vr.set( + xlabel="r [R$_\\odot$]", ylabel="v$_r$ [km/s$^{-1}$]", + ylim=(0, 800) + ) + -DATA_LOCATION = +if __name__ == "__main__": + main()