From aff78525a8080adc178b4c26508f67cb46bea62d Mon Sep 17 00:00:00 2001 From: "Karl N. Kappler" Date: Sun, 21 Jul 2024 15:51:41 -0700 Subject: [PATCH] merge some doc from 337 branch to test --- aurora/sandbox/debug_mt_metadata_issue_85.py | 5 ++ .../sandbox/mth5_channel_summary_helpers.py | 8 ++- aurora/sandbox/mth5_helpers.py | 40 +++++++---- aurora/sandbox/obspy_helpers.py | 22 ++++-- aurora/sandbox/plot_helpers.py | 71 ++++++++++++++----- aurora/sandbox/triage_metadata.py | 26 +++++-- 6 files changed, 128 insertions(+), 44 deletions(-) diff --git a/aurora/sandbox/debug_mt_metadata_issue_85.py b/aurora/sandbox/debug_mt_metadata_issue_85.py index f989b43b..3f2255a2 100644 --- a/aurora/sandbox/debug_mt_metadata_issue_85.py +++ b/aurora/sandbox/debug_mt_metadata_issue_85.py @@ -1,7 +1,12 @@ +""" + This module contains a test that should be moved into mt_metadata + TODO: Make this a test in mt_metadata +""" from mt_metadata.timeseries.location import Location from mth5.mth5 import MTH5 from loguru import logger + def test_can_add_location(): """ 20220624: This mini test is being factored out of the normal tests. diff --git a/aurora/sandbox/mth5_channel_summary_helpers.py b/aurora/sandbox/mth5_channel_summary_helpers.py index 2ba113b0..a4efc6c0 100644 --- a/aurora/sandbox/mth5_channel_summary_helpers.py +++ b/aurora/sandbox/mth5_channel_summary_helpers.py @@ -1,11 +1,17 @@ +""" + This module contains methods to help make mth5 files. + TODO: Review and move to make_mth5 if relevant +""" import pandas as pd from loguru import logger def channel_summary_to_make_mth5( - df, network="", channel_nomenclature=None, verbose=False + df: pd.DataFrame, network="", channel_nomenclature=None, verbose=False ): """ + Makes a dataframe that can be passed to make_mth5. + Context is say you have a station_xml that has come from somewhere and you want to make an mth5 from it, with all the relevant data. Then you should use make_mth5. But make_mth5 wants a df with a particular schema (which should be diff --git a/aurora/sandbox/mth5_helpers.py b/aurora/sandbox/mth5_helpers.py index d3d3fbdc..29a5b8bc 100644 --- a/aurora/sandbox/mth5_helpers.py +++ b/aurora/sandbox/mth5_helpers.py @@ -1,12 +1,12 @@ """ -This module was inside of mth5/clients/helper_functions.py -on branch issue_76_make_mth5_factoring +This module contains utility functions for working with MTH5 files. +TODO: Review and move to mth5 if relevant -Some of these functions are handy, and should eventually be merged into mth5. +Background: This module was inside of mth5/clients/helper_functions.py on branch issue_76_make_mth5_factoring -I would also like to use some of these functions from time-to-time, so I am putting -them here for now, until we can decide what to move to mth5 and what to keep in -aurora (and what to throw out). +Some of these functions are handy, and should eventually be merged into mth5. I would also like to +use some of these functions from time-to-time, so I am putting them here for now, until we can +decide what to move to mth5 and what to keep in aurora (and what to throw out). """ import datetime import pandas as pd @@ -19,6 +19,7 @@ def enrich_channel_summary(mth5_object, df, keyword): """ + Operates on a channel summary df and adds some information in a new column. Parameters ---------- @@ -59,10 +60,15 @@ def enrich_channel_summary(mth5_object, df, keyword): return df -def augmented_channel_summary(mth5_object, df=None): # , **kwargs): +def augmented_channel_summary(mth5_object, df=None): """ - Consider supportig kwargs, such as a list of keyords that tell what columns to add - For now, we only want to add n_filters + Adds column "n_filters" to mth5 channel summary. + + This function was used when debugging and wide scale testing at IRIS/Earthscope. + + Development Notes: + TODO: Consider supporting a list of keyeords that tell what columns to add + Parameters ---------- df: channel summary dataframe @@ -70,7 +76,8 @@ def augmented_channel_summary(mth5_object, df=None): # , **kwargs): Returns ------- - + df: pd.Dataframe + Same as input but with new column """ if not df: df = mth5_object.channel_summary.to_dataframe() @@ -92,8 +99,10 @@ def build_request_df( end=None, time_period_dict={}, mth5_version="0.2.0", -): +) -> pd.DataFrame: """ + Given some information about an earthscope dataset, format the dataset description + into a request_df dataframe. Parameters ---------- @@ -116,10 +125,7 @@ def build_request_df( Returns ------- - - - Returns: - request_df: pd.DataFrame + request_df: pd.DataFrame A formatted dataframe that can be passed to mth5.clients.FDSN to request metdata or data. """ @@ -159,6 +165,7 @@ def get_time_period_bounds(ch): def get_experiment_from_obspy_inventory(inventory): + """Converts an FDSN inventory to an MTH5 Experiment object""" translator = XMLInventoryMTExperiment() experiment = translator.xml_to_mt(inventory_object=inventory) return experiment @@ -166,6 +173,7 @@ def get_experiment_from_obspy_inventory(inventory): def mth5_from_experiment(experiment, h5_path=None): """ + Converts an experiment object into an mth5 file. Parameters ---------- @@ -183,6 +191,8 @@ def mth5_from_experiment(experiment, h5_path=None): def get_channel_summary(h5_path): """ + Gets a channel summary from an mth5; + TODO: This can be replaced by methods in mth5. Parameters ---------- diff --git a/aurora/sandbox/obspy_helpers.py b/aurora/sandbox/obspy_helpers.py index b1cb5088..69138651 100644 --- a/aurora/sandbox/obspy_helpers.py +++ b/aurora/sandbox/obspy_helpers.py @@ -1,3 +1,10 @@ +""" + This module contains helper functions for working with obspy objects. + + Development Notes + - TODO: Most of this could likely be moved into MTH5 + +""" import datetime from obspy import UTCDateTime @@ -6,9 +13,8 @@ def trim_streams_to_acquisition_run(streams): """ - Rename as? TRIM DATA STREAMS TO COMMON TIME STAMPS - TODO: add doc here. It looks like we are slicing from the earliest starttime to - the latest endtime + Slices streams to common time stamps. + Parameters ---------- streams @@ -25,6 +31,8 @@ def trim_streams_to_acquisition_run(streams): def align_streams(streams, clock_start): """ + Shift stream timestamps so that they are aligned. + This is a hack around to handle data that are asynchronously sampled. It should not be used in general. It is only appropriate for datasets that have been tested with it. @@ -38,7 +46,7 @@ def align_streams(streams, clock_start): Returns ------- - + streams """ for stream in streams: logger.info( @@ -73,6 +81,8 @@ def align_streams(streams, clock_start): def make_channel_labels_fdsn_compliant(streams): """ + Renames channels to FDSN compliant channel names. + Workaround because NCEDC channel nomenclature is not FDSN Compliant for PKD, SAO Specifically, re-assign non-conventional channel labels Q2 --> Q1 @@ -85,6 +95,10 @@ def make_channel_labels_fdsn_compliant(streams): ---------- streams : iterable of types obspy.core.stream.Stream + Returns + ------- + streams : iterable of types obspy.core.stream.Stream + Same as input but updated with new channel names. """ for stream in streams: stream.stats["channel"] = FDSN_CHANNEL_MAP[stream.stats["channel"]] diff --git a/aurora/sandbox/plot_helpers.py b/aurora/sandbox/plot_helpers.py index c6dcdeed..01905b26 100644 --- a/aurora/sandbox/plot_helpers.py +++ b/aurora/sandbox/plot_helpers.py @@ -1,19 +1,30 @@ -from matplotlib.gridspec import GridSpec +""" + This module contains some plotting helper functions. + + Most of these were used in initial development and should be replaced by methods in MTpy. + TODO: review which of these can be replaced with methods in MTpy-v2 +""" +from matplotlib.gridspec import GridSpec +from typing import Optional, Union import matplotlib.pyplot as plt import numpy as np import scipy.signal as ssig -def is_flat_amplitude(array): +def _is_flat_amplitude(array) -> bool: """ - Check of an amplitude response is basically flat. If so, it is best to tune the y-axis lims to - make numeric noise invisible + Check of an amplitude response is basically flat. + + If so, it is best to tune the y-axis lims to make numeric noise invisible. + Parameters ---------- - array + array: the response of some stage as a function of frequency. Returns ------- + bool: + True is response is flat, False otherwise """ differences = np.diff(np.abs(array)) if np.isclose(differences, 0.0).all(): @@ -23,6 +34,22 @@ def is_flat_amplitude(array): def cast_angular_frequency_to_period_or_hertz(w, units): + """ + Converts angular frequency to period or Hertz + + Parameters + ---------- + w: numpy array + Angular frequencies (radians per second) + units: str + Requested output units ("period" or "frequency") + + Returns + ------- + x_axis: np.ndarray + Same as input but units are now the requested ones. + + """ if units.lower() == "period": x_axis = (2.0 * np.pi) / w elif units.lower() == "frequency": @@ -30,22 +57,26 @@ def cast_angular_frequency_to_period_or_hertz(w, units): return x_axis -def plot_complex_response(frequency, complex_response, **kwargs): +def plot_complex_response( + frequency: np.ndarray, + complex_response: np.ndarray, + show: Optional[bool] = True, + linewidth: Optional[float] = 3, + make: Optional[Union[str, None]] = None, + model: Optional[Union[str, None]] = None, + yamp: Optional[Union[str, None]] = None, +): """ - ToDo: add methods for suporting instrument object but for now take as kwargs + Plots amplitude and phase of a complex response as a function of frequency. + + Development Notes: + ToDo: add methods for supporting instrument object but for now take as kwargs + :param frequency: numpy array of frequencies at which complex response is defined :param complex_response: numpy array of full complex valued response function - :param kwargs: :return: """ - - show = kwargs.get("show", True) - linewidth = kwargs.get("linewidth", 3) - - make = kwargs.get("make", None) - model = kwargs.get("model", None) - y_amp_string = kwargs.get("yamp", None) - + y_amp_string = yamp amplitude = np.abs(complex_response) phase = np.angle(complex_response) @@ -77,6 +108,8 @@ def plot_response_pz( x_units="Period", ): """ + Plots the pole zero response. + This function was contributed by Ben Murphy at USGS 2021-03-17: there are some issues encountered when using this function to plot generic resposnes, looks like the x-axis gets out of order when using frequency @@ -114,7 +147,7 @@ def plot_response_pz( if w_obs is not None and resp_obs is not None: response_amplitude = np.absolute(resp_obs) - if is_flat_amplitude(resp_obs): + if _is_flat_amplitude(resp_obs): response_amplitude[:] = response_amplitude[0] ax_amp.set_ylim([0.9 * response_amplitude[0], 1.1 * response_amplitude[0]]) x_values = cast_angular_frequency_to_period_or_hertz(w_obs, x_units) @@ -250,7 +283,9 @@ def plot_response_pz( def plot_tf_obj(tf_obj, out_filename=None, show=True): """ - To Do: Get plotter from MTpy or elsewhere. + Plot the transfer function object in terms of apparent resistivity and phase + + TODO: Get plotter from MTpy or elsewhere. See Issue #209 https://github.com/simpeg/aurora/issues/209 Parameters diff --git a/aurora/sandbox/triage_metadata.py b/aurora/sandbox/triage_metadata.py index 63d0cc2b..c655ac61 100644 --- a/aurora/sandbox/triage_metadata.py +++ b/aurora/sandbox/triage_metadata.py @@ -1,3 +1,7 @@ +""" + This module contains various helper functions that were used to fix errors in metadata. +""" + from mt_metadata.timeseries.filters.helper_functions import MT2SI_ELECTRIC_FIELD_FILTER from mt_metadata.timeseries.filters.helper_functions import MT2SI_MAGNETIC_FIELD_FILTER @@ -6,11 +10,14 @@ def triage_mt_units_electric_field(experiment): """ + Updates an mth5 experiment with filter information + One-off example of adding a filter to an mth5 in the case where the electric field data are given in V/m, but they were expected in mV/km. This adds the correct filter to the metadata so that the calibrated data have units of mV/km. - Parameters + + Parameters ---------- experiment ; @@ -37,11 +44,13 @@ def triage_mt_units_electric_field(experiment): def triage_mt_units_magnetic_field(experiment): """ - One-off example of adding a filter to an mth5 in the case where the electric - field data are given in V/m, but they were expected in mV/km. This adds the - correct filter to the metadata so that the calibrated data have units of - mV/km. - Parameters + Updates an mth5 experiment with filter information + + One-off example of adding a filter to an mth5 in the case where the magnetic + field data are given in T, but they were expected in nT. This adds the + correct filter to the metadata so that the calibrated data have units of nT. + + Parameters ---------- experiment ; @@ -68,7 +77,10 @@ def triage_mt_units_magnetic_field(experiment): def triage_missing_coil_hollister(experiment): """ + Fixes missing metadata for Hollister station + One off for hollister missing hy metadata for no reason I can tell + Parameters ---------- experiment @@ -95,6 +107,8 @@ def triage_missing_coil_hollister(experiment): def triage_run_id(expected_run_id, run_obj): """ + Fixes metadata from an old version of MTH5. + This situation was encounterd during the Musgraves processing in 2023 HPC workshopl The MTH5 files being used were from a previous era, and the run_object metadata did not contain the expected value for run_id.