Source code for pyacs.gts.lib.model.detrend

###################################################################
[docs] def detrend(self, method='L2', periods=[], exclude_periods=[], log_dir=None): ################################################################### """Detrend time series and store velocity (and optional offsets) in attributes. Parameters ---------- method : str, optional Estimation method (e.g. 'L2'). Default is 'L2'. periods : list, optional Periods used for velocity estimate. Default is []. exclude_periods : list, optional Periods excluded from velocity estimate. Default is []. log_dir : str, optional Directory for Gts-specific log file {self.code}.log. Default is None. Returns ------- Gts Detrended time series (velocity attribute set). Notes ----- Outliers in Gts.outliers are omitted; offsets in Gts.offsets_dates are estimated simultaneously. """ import numpy as np from pyacs.gts.Gts import Gts import inspect import logging import os import pyacs.message.message as MESSAGE import pyacs.message.verbose_message as VERBOSE import pyacs.message.error as ERROR import pyacs.message.warning as WARNING import pyacs.message.debug_message as DEBUG # Setup Gts-specific logging if log_dir is provided gts_logger = None if log_dir is not None: # Create log directory if it doesn't exist os.makedirs(log_dir, exist_ok=True) # Create Gts-specific log file log_file = os.path.join(log_dir, f"{self.code}.log") # Configure Gts-specific logger gts_logger = logging.getLogger(f'pyacs.gts.{self.code}') if not gts_logger.handlers: gts_logger.setLevel(logging.INFO) # Prevent propagation to parent loggers to avoid duplicate logging gts_logger.propagate = False file_handler = logging.FileHandler(log_file, mode='a') # append mode file_handler.setLevel(logging.INFO) # Custom formatter with [Gts.code] prefix formatter = logging.Formatter('%(asctime)s - %(levelname)s - [%(name)s] %(message)s') file_handler.setFormatter(formatter) gts_logger.addHandler(file_handler) # Log method start with [Gts.code] prefix gts_logger.info(f"[{self.code}] [detrend] Starting method") gts_logger.info(f"[{self.code}] [detrend] Parameters: method={method}") gts_logger.info(f"[{self.code}] [detrend] Time series: {len(self.data)} points from {self.data[0, 0]:.3f} to {self.data[-1, 0]:.3f}") if periods: gts_logger.info(f"[{self.code}] [detrend] Using periods: {periods}") if exclude_periods: gts_logger.info(f"[{self.code}] [detrend] Excluding periods: {exclude_periods}") # after this method .data and .data_xyz are not consistent so .data_xyz is set to None #self.data_xyz = None ########################################################################### # check data is not None from pyacs.gts.lib.errors import GtsInputDataNone try: if self.data is None: # raise exception raise GtsInputDataNone(inspect.stack()[0][3], __name__, self) except GtsInputDataNone as error: # print PYACS WARNING if gts_logger: gts_logger.error(f"[{self.code}] [detrend] Input data is None") ERROR(error) return (self) ########################################################################### if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Starting main processing") import copy outliers = copy.deepcopy(self.outliers) tmp_ts = self.remove_outliers() if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Removed outliers, remaining points: {len(tmp_ts.data)}") if periods != []: tmp_ts = tmp_ts.extract_periods(periods) if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Extracted periods, remaining points: {len(tmp_ts.data)}") if exclude_periods != []: tmp_ts = tmp_ts.exclude_periods(periods) if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Excluded periods, remaining points: {len(tmp_ts.data)}") if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Creating model with method={method}") detrended = tmp_ts.make_model(option='detrend', method=method) vel = detrended.velocity offsets_values = detrended.offsets_values if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Model created successfully") gts_logger.info(f"[{self.code}] [detrend] Velocity estimates (N,E,U, mm/yr): [{vel[0]*1.E3:.3f}, {vel[1]*1.E3:.3f}, {vel[2]*1.E3:.3f}]") if len(vel) > 3: gts_logger.info(f"[{self.code}] [detrend] Velocity uncertainties (N,E,U, mm/yr): [{vel[3]*1.E3:.3f}, {vel[4]*1.E3:.3f}, {vel[5]*1.E3:.3f}]") if offsets_values is not None and len(offsets_values) > 0: gts_logger.info(f"[{self.code}] [detrend] Estimated {len(offsets_values)} offsets") new_gts = self.copy() new_gts.outliers = outliers new_gts.offsets_values = offsets_values new_gts.velocity = vel if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Creating model time series") model = new_gts.mmodel() if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Subtracting model from data") new_gts.data[:, 1:4] = new_gts.data[:, 1:4] - model.data[:, 1:4] if gts_logger: gts_logger.info(f"[{self.code}] [detrend] Method completed successfully") return (new_gts)