def _check_input(values_dict): """Perform checks on inputs. Specifically: 1. Ensure all components are `TimeSeries` objects. 2. Ensure all components have equal `dt`. 3. Ensure all components have same `nsamples`, if not trim. Parameters ---------- values_dict : dict Key is human-readable component name {'ns', 'ew', 'vt'}. Value is corresponding `TimeSeries` object. Returns ------- Tuple Containing checked components as tuple of the form `(ns, ew, vt)`. """ ns = values_dict["ns"] try: ns = TimeSeries.from_timeseries(ns) except AttributeError as e: msg = f"'ns' must be a `TimeSeries`, not {type(ns)}." raise TypeError(msg) from e values_dict["ns"] = ns dt = ns.dt nsamples = ns.nsamples for key, value in values_dict.items(): if key == "ns": continue if isinstance(value, TimeSeries): values_dict[key] = TimeSeries.from_timeseries(value) else: msg = f"`{key}`` must be a `TimeSeries`, not {type(value)}." raise TypeError(msg) if value.dt != dt: msg = "All components must have equal `dt`." raise ValueError(msg) if value.nsamples != nsamples: txt = "".join( [f"{_k}={_v.nsamples} " for _k, _v in values_dict.items()]) msg = f"Components are different length: {txt}" raise ValueError(msg) return (values_dict["ns"], values_dict["ew"], values_dict["vt"])
def from_dict(cls, dictionary): """Create `Sensor3c` object from dictionary representation. Parameters --------- dictionary : dict Must contain keys "ns", "ew", and "vt", and may also contain the optional key "meta". "ns", "ew", and "vt" must be dictionary representations of `TimeSeries` objects, see `SigProPy <https://sigpropy.readthedocs.io/en/latest/?badge=latest>`_ documentation for details. Returns ------- Sensor3c Instantiated `Sensor3c` object. """ if dictionary.get("meta") is None: dictionary["meta"] = None comps = [] for comp in ["ns", "ew", "vt"]: comps.append(TimeSeries.from_dict(dictionary[comp])) return cls(*comps, dictionary["meta"])
def reload_file(self): logging.info("begin - reload_file()") # Reset state self.applied_filter = False self.applied_taper = False self.fseries = False # Load File and Update Plot to Reflect This if self.fname.endswith(".miniseed"): traces = obspy.read(self.fname) self.tseries = TimeSeries.from_trace(traces[0]) else: df = pd.read_csv(self.fname, names=["time", "amp"]) self.tseries = TimeSeries(df.amp.to_numpy(), df.time[1] - df.time[0]) self.update_tseries_plot() self.update_fseries_plot()
def from_mseed(cls, fname): """Initialize a 3-component sensor (Sensor3c) object from a .miniseed file. Parameters ---------- fname : str Name of miniseed file, full path may be used if desired. The file should contain three traces with the appropriate channel names. Refer to the `SEED` Manual `here <https://www.fdsn.org/seed_manual/SEEDManual_V2.4.pdf>`_. for specifics. Returns ------- Sensor3c Initialized 3-component sensor object. """ traces = obspy.read(fname) if len(traces) != 3: msg = f"miniseed file {fname} has {len(traces)} traces, but should have 3." raise ValueError(msg) found_ew, found_ns, found_vt = False, False, False for trace in traces: if trace.meta.channel.endswith("E") and not found_ew: ew = TimeSeries.from_trace(trace) found_ew = True elif trace.meta.channel.endswith("N") and not found_ns: ns = TimeSeries.from_trace(trace) found_ns = True elif trace.meta.channel.endswith("Z") and not found_vt: vt = TimeSeries.from_trace(trace) found_vt = True else: msg = f"Missing, duplicate, or incorrectly named components. See documentation." raise ValueError(msg) meta = {"File Name": fname} return cls(ns, ew, vt, meta)
def _combine_horizontal_td(self, method, horizontals, azimuth): az_rad = math.radians(azimuth) ns = horizontals["ns"] ew = horizontals["ew"] if method in ["azimuth", "single-azimuth"]: horizontal = ns.amp*math.cos(az_rad) + ew.amp*math.sin(az_rad) else: msg = f"method={method} has not been implemented." raise NotImplementedError(msg) if isinstance(ns, WindowedTimeSeries): return WindowedTimeSeries(horizontal, ns.dt) elif isinstance(ns, TimeSeries): return TimeSeries(horizontal, ns.dt) else: raise NotImplementedError
def _combine_horizontal_td(self, method, azimuth): """Combine horizontal components in the time domain. azimuth : float, optional Azimuth (clockwise positive) from North (i.e., 0 degrees). Returns ------- TimeSeries Representing the combined horizontal components. """ az_rad = math.radians(azimuth) if method in ["azimuth", "single-azimuth"]: horizontal = self.ns._amp * \ math.cos(az_rad) + self.ew._amp*math.sin(az_rad) else: msg = f"method={method} has not been implemented." raise NotImplementedError(msg) return TimeSeries(horizontal, self.ns.dt)
def from_saf(cls, fname): """Create `Sensor3c` object from a SAF ASCII file. Parameters --------- fname : str Name of the SESAME ASCII (SAF) file. Returns ------- Sensor3c Instantiated `Sensor3c` object. """ meta = {} meta["File Name"] = fname # This is the default value if a project name is not provided. meta["project_name"] = PROJECT_NAME meta["evt_x"] = EVT_X meta["evt_y"] = EVT_Y meta["evt_z"] = EVT_Z with open(fname) as fsaf: # Look for some parameters in the header and # for the line where data start. for num, line in enumerate(fsaf, 1): spl = line.split(sep=SAF_SEP) # Remove all white spaces spl = [s.replace(" ", "") for s in spl] if "####----" in line: # Data should start from here data_start = num break if spl: # List is not empty # print(spl) if spl[0] == "SAMP_FREQ": # Collect the sampling frequency # CHECK HERE IF THE SAMPLING FREQUENCY IS OK! samp_freq = float(spl[1]) elif spl[0] == "PROJECT_NAME": try: # Collect the name of the project project_name = spl[1] except IndexError: # No name provided for the project project_name = "None" meta["project_name"] = project_name elif spl[0] == "START_TIME": # print(spl[1]) YYYY = int(spl[1][:4]) MM = int(spl[1][4:6]) DD = int(spl[1][6:8]) hh = int(spl[1][8:10]) mm = int(spl[1][10:12]) ss = int(spl[1][12:14]) # print(YYYY, MM, DD) starttime = obspy.UTCDateTime(YYYY, MM, DD, hh, mm, ss) meta["starttime"] = (spl[1][:4]+"/"+spl[1][4:6]+"/"+spl[1][6:8]+" " +spl[1][8:10]+":"+spl[1][10:12]+":"+spl[1][12:14]) elif spl[0] == "EVT_X": meta["evt_x"] = float(spl[1]) elif spl[0] == "EVT_Y": meta["evt_y"] = float(spl[1]) elif spl[0] == "EVT_Z": meta["evt_z"] = float(spl[1]) # Read the dataset unsing pandas data = pd.read_csv(fname, sep=r"\s+", skiprows=data_start, header=None, float_precision="round_trip") data.rename(columns={0: "vt",1: "ns", 2:"ew"}, inplace=True) trace_ew = obspy.Trace() trace_ew.data = data["ew"].to_numpy() trace_ew.stats.sampling_rate = samp_freq trace_ew.stats.starttime = starttime ew = TimeSeries.from_trace(trace_ew) trace_ns = obspy.Trace() trace_ns.data = data["ns"].to_numpy() trace_ns.stats.sampling_rate = samp_freq trace_ns.stats.starttime = starttime ns = TimeSeries.from_trace(trace_ns) trace_vt = obspy.Trace() trace_vt.data = data["vt"].to_numpy() trace_vt.stats.sampling_rate = samp_freq trace_vt.stats.starttime = starttime vt = TimeSeries.from_trace(trace_vt) return cls(ns, ew, vt, meta)
def from_mseed(cls, fname=None, fnames_1c=None): """Create 3-component sensor (Sensor3c) object from .mseed file. Parameters ---------- fname : str, optional Name of miniseed file, full path may be used if desired. The file should contain three traces with the appropriate channel names. Refer to the `SEED` Manual `here <https://www.fdsn.org/seed_manual/SEEDManual_V2.4.pdf>`_. for specifics, default is `None`. fnames_1c : dict, optional Some data acquisition systems supply three separate miniSEED files rather than a single combined file. To use those types of files, simply specify the three files in a `dict` of the form `{'e':'east.mseed', 'n':'north.mseed', 'z':'vertical.mseed'}`, default is `None`. Returns ------- Sensor3c Initialized 3-component sensor object. Raises ------ ValueError If both `fname` and `fname_verbose` are `None`. """ if fnames_1c is None and fname is None: msg = "`fnames_1c` and `fname` cannot both be `None`." raise ValueError(msg) if fnames_1c is not None: trace_list = [] for key in ["e", "n", "z"]: stream = obspy.read(fnames_1c[key], format="MSEED") if len(stream) > 1: msg = f"File {fnames_1c[key]} contained {len(stream)}" msg += "traces, rather than 1 as was expected." raise IndexError(msg) trace = stream[0] if trace.meta.channel[-1] != key.capitalize(): msg = "Component indicated in the header of " msg += f"{fnames_1c[key]} is {trace.meta.channel[-1]} " msg += f"which does not match the key {key} specified. " msg += "Ignore this warning only if you know " msg += "your digitizer's header is incorrect." warnings.warn(msg) trace.meta.channel = trace.meta.channel[:-1] + \ key.capitalize() trace_list.append(trace) traces = obspy.Stream(trace_list) else: traces = obspy.read(fname, format="MSEED") if len(traces) != 3: msg = f"miniseed file {fname} has {len(traces)} traces, but should have 3." raise ValueError(msg) found_ew, found_ns, found_vt = False, False, False for trace in traces: if trace.meta.channel.endswith("E") and not found_ew: ew = TimeSeries.from_trace(trace) found_ew = True elif trace.meta.channel.endswith("N") and not found_ns: ns = TimeSeries.from_trace(trace) found_ns = True elif trace.meta.channel.endswith("Z") and not found_vt: vt = TimeSeries.from_trace(trace) found_vt = True else: msg = "Missing, duplicate, or incorrectly named components. See documentation." raise ValueError(msg) meta = {"File Name": fname} return cls(ns, ew, vt, meta)