From 8e82b9c5aa305589a1fe7326de81c4f0cafaee12 Mon Sep 17 00:00:00 2001 From: Martin Vonk Date: Tue, 27 Dec 2022 11:19:18 +0100 Subject: [PATCH] resolve some issues --- pastas/model.py | 2 +- pastas/modelplots.py | 13 ++++++++++--- pastas/modelstats.py | 2 +- pastas/noisemodels.py | 2 +- pastas/plots.py | 8 +++----- pastas/rfunc.py | 40 +++++++++++++++----------------------- pastas/solver.py | 2 +- pastas/stats/dutch.py | 4 ++-- pastas/stats/signatures.py | 4 ++-- pastas/stressmodels.py | 2 +- pastas/typeh.py | 2 +- 11 files changed, 39 insertions(+), 42 deletions(-) diff --git a/pastas/model.py b/pastas/model.py index da344697d..3a8026c6e 100644 --- a/pastas/model.py +++ b/pastas/model.py @@ -960,7 +960,7 @@ def get_tmin(self, tmin: Optional[pstTm] = None, use_oseries: Optional[bool] = T return tmin - def get_tmax(self, tmin: Optional[pstTm] = None, use_oseries: Optional[bool] = True, use_stresses: Optional[bool] = False) -> Type[Timestamp]: + def get_tmax(self, tmax: Optional[pstTm] = None, use_oseries: Optional[bool] = True, use_stresses: Optional[bool] = False) -> Type[Timestamp]: """Method that checks and returns valid values for tmax. Parameters diff --git a/pastas/modelplots.py b/pastas/modelplots.py index 2cadb1c76..d6556bd89 100644 --- a/pastas/modelplots.py +++ b/pastas/modelplots.py @@ -8,7 +8,7 @@ import numpy as np from matplotlib.backends.backend_pdf import PdfPages from matplotlib.ticker import MultipleLocator, LogFormatter -from pandas import concat, Timestamp, Series +from pandas import concat, Series from .decorators import model_tmin_tmax from .plots import series, diagnostics, cum_frequency, \ @@ -687,7 +687,7 @@ def contributions_pie(self, tmin: Optional[pstTm] = None, tmax: Optional[pstTm] @model_tmin_tmax def stacked_results(self, tmin: Optional[pstTm] = None, tmax: Optional[pstTm] = None, figsize: Optional[tuple] = (10, 8), - stacklegend: Optional[bool] = False, **kwargs) -> pstAx: + stacklegend: Optional[bool] = False, stacklegend_kws: Optional[dict] = None, **kwargs) -> pstAx: """Create a results plot, similar to `ml.plots.results()`, in which the individual contributions of stresses (in stressmodels with multiple stresses) are stacked. @@ -802,7 +802,7 @@ def series(self, tmin: Optional[pstTm] = None, tmax: Optional[pstTm] = None, spl @model_tmin_tmax def summary_pdf(self, tmin: Optional[pstTm] = None, tmax: Optional[pstTm] = None, fname: Optional[str] = None, dpi: Optional[int] = 150, - results_kwargs: Optional[dict] = {}, diagnostics_kwargs: Optional[dict] = {}): + results_kwargs: Optional[dict] = None, diagnostics_kwargs: Optional[dict] = None): """Create a PDF file (A4) with the results and diagnostics plot. Parameters @@ -825,6 +825,13 @@ def summary_pdf(self, tmin: Optional[pstTm] = None, tmax: Optional[pstTm] = None """ if fname is None: fname = "{}.pdf".format(self.ml.name) + + if results_kwargs is None: + results_kwargs = {} + + if diagnostics_kwargs is None: + diagnostics_kwargs = {} + pdf = PdfPages(fname) fig = plt.figure(figsize=(8.27, 11.69), dpi=50) diff --git a/pastas/modelstats.py b/pastas/modelstats.py index 7408a8c58..e49c8066c 100644 --- a/pastas/modelstats.py +++ b/pastas/modelstats.py @@ -27,7 +27,7 @@ from .decorators import model_tmin_tmax from .stats import diagnostics, metrics -from .typeh import Type, Union, Optional, pstMl, pstTm +from .typeh import Type, Optional, pstMl, pstTm class Statistics: diff --git a/pastas/noisemodels.py b/pastas/noisemodels.py index d1250bc6f..9f45dd330 100644 --- a/pastas/noisemodels.py +++ b/pastas/noisemodels.py @@ -179,7 +179,7 @@ def weights(self, res: Type[Series], p: pstAL) -> Type[Series]: .. math:: w = 1 / sqrt((1 - exp(-2 \\Delta t / \\alpha))) which are then normalized so that sum(w) = len(res). -Ò + """ alpha = p[0] # large for first measurement diff --git a/pastas/plots.py b/pastas/plots.py index 43cc2b82d..16e3dbe96 100644 --- a/pastas/plots.py +++ b/pastas/plots.py @@ -12,7 +12,7 @@ from pastas.stats.core import acf as get_acf from pastas.stats.metrics import rmse, evp from pastas.typeh import Type, Optional, pstAx, pstFi, pstTm, pstMl, pstAL - +from pastas.modelcompare import CompareModels logger = logging.getLogger(__name__) @@ -20,8 +20,7 @@ "TrackSolve"] -def compare(models: list[pstMl], tmin: Optional[pstTm] = None, tmax: Optional[pstTm] = None, block_or_step: Optional[str] = 'step', - adjust_height: Optional[bool] = True, **kwargs) -> pstAx: +def compare(models: list[pstMl], adjust_height: Optional[bool] = True, **kwargs) -> pstAx: """Plot multiple Pastas models in one figure to visually compare models. Note @@ -195,8 +194,7 @@ def series(head: Optional[Type[Series]] = None, stresses: Optional[list[Type[Ser def acf(series: Type[Series], alpha: Optional[float] = 0.05, lags: Optional[int] = 365, acf_options: Optional[dict] = None, smooth_conf: Optional[bool] = True, - ax: Optional[pstAx] = None, figsize: Optional[tuple] = (5, 2)): - + color: Optional[str] = "k", ax: Optional[pstAx] = None, figsize: Optional[tuple] = (5, 2)): """Plot of the autocorrelation function of a time series. Parameters diff --git a/pastas/rfunc.py b/pastas/rfunc.py index 51ad6d48d..3456bef59 100644 --- a/pastas/rfunc.py +++ b/pastas/rfunc.py @@ -6,7 +6,7 @@ import numpy as np from pandas import DataFrame from scipy.integrate import quad -from scipy.special import (erfc, erfcinv, exp1, gamma, gammainc, gammaincinv, +from scipy.special import (erfc, erfcinv, exp1, gamma, gammainc, gammaincinv, k0, k1, lambertw) from scipy.interpolate import interp1d @@ -117,7 +117,7 @@ def block(self, p: pstAL, dt: Optional[float] = 1.0, cutoff: Optional[float] = N """ s = self.step(p, dt, cutoff, maxtmax) return np.append(s[0], np.subtract(s[1:], s[:-1])) - + def impulse(self, t, p): """Method to return the impulse response function. @@ -137,7 +137,7 @@ def impulse(self, t, p): ------- s: numpy.array Array with the impulse response. - + Note ---- Only used for internal consistency checks @@ -237,7 +237,7 @@ def step(self, p: pstAL, dt: Optional[float] = 1.0, cutoff: Optional[float] = No t = self.get_t(p, dt, cutoff, maxtmax) s = p[0] * gammainc(p[1], t / p[2]) return s - + def impulse(self, t, p): A, n, a = p ir = A * t ** (n - 1) * np.exp(-t / a) / (a ** n * gamma(n)) @@ -268,7 +268,6 @@ class Exponential(RfuncBase): """ _name = "Exponential" - def __init__(self): RfuncBase.__init__(self) self.nparam = 2 @@ -302,7 +301,7 @@ def step(self, p: pstAL, dt: Optional[float] = 1.0, cutoff: Optional[float] = No t = self.get_t(p, dt, cutoff, maxtmax) s = p[0] * (1.0 - np.exp(-t / p[1])) return s - + def impulse(self, t, p): A, a = p ir = A / a * np.exp(-t / a) @@ -341,7 +340,6 @@ class HantushWellModel(RfuncBase): """ _name = "HantushWellModel" - def __init__(self): RfuncBase.__init__(self) self.distances = None @@ -398,7 +396,7 @@ def get_tmax(self, p: pstAL, cutoff: Optional[float] = None) -> float: else: return lambertw(1 / ((1 - cutoff) * k0rho)).real * cS - def gain(self, p: pstAL: r: Optional[float] = None) -> float: + def gain(self, p: pstAL, r: Optional[float] = None) -> float: if r is None: r = self._get_distance_from_params(p) rho = 2 * r * np.sqrt(p[2]) @@ -464,11 +462,11 @@ def variance_gain(A: float, b: float, var_A: float, var_b: float, cov_Ab: float, ps.WellModel.variance_gain """ var_gain = ( - (k0(2 * np.sqrt(r ** 2 * b))) ** 2 * var_A + - (-A * r * k1(2 * np.sqrt(r ** 2 * b)) / np.sqrt( - b)) ** 2 * var_b - - 2 * A * r * k0(2 * np.sqrt(r ** 2 * b)) * - k1(2 * np.sqrt(r ** 2 * b)) / np.sqrt(b) * cov_Ab + (k0(2 * np.sqrt(r ** 2 * b))) ** 2 * var_A + + (-A * r * k1(2 * np.sqrt(r ** 2 * b)) / np.sqrt( + b)) ** 2 * var_b - + 2 * A * r * k0(2 * np.sqrt(r ** 2 * b)) * + k1(2 * np.sqrt(r ** 2 * b)) / np.sqrt(b) * cov_Ab ) return var_gain @@ -506,7 +504,6 @@ class Hantush(RfuncBase): """ _name = "Hantush" - def __init__(self): RfuncBase.__init__(self) self.nparam = 3 @@ -555,7 +552,7 @@ def step(self, p: pstAL, dt: float = 1.0, cutoff: Optional[float] = None, maxtma F[tau >= rho / 2] = 2 * k0rho - w * exp1(tau2) + (w - 1) * exp1( tau2 + rho ** 2 / (4 * tau2)) return p[0] * F / (2 * k0rho) - + def impulse(self, t, p): A, a, b = p ir = A / (2 * t * k0(2 * np.sqrt(b))) * np.exp(-t / a - a * b / t) @@ -620,10 +617,10 @@ def step(self, p: pstAL, dt: Optional[float] = 1.0, cutoff: Optional[float] = No if not self.up: s = -s return s - + def impulse(self, t, p): A, a, b = p - ir = A * t ** (-1.5) * np.exp(-t / a - b / t) + ir = A * t ** (-1.5) * np.exp(-t / a - b / t) return ir @staticmethod @@ -649,7 +646,6 @@ class One(RfuncBase): """ _name = "One" - def __init__(self): RfuncBase.__init__(self) self.nparam = 1 @@ -710,7 +706,6 @@ class FourParam(RfuncBase): """ _name = "FourParam" - def __init__(self, quad=False): RfuncBase.__init__(self, quad=quad) self.nparam = 4 @@ -859,7 +854,6 @@ class DoubleExponential(RfuncBase): """ _name = "DoubleExponential" - def __init__(self): RfuncBase.__init__(self) self.nparam = 4 @@ -993,7 +987,6 @@ class Kraijenhoff(RfuncBase): """ _name = "Kraijenhoff" - def __init__(self, n_terms=10): RfuncBase.__init__(self, n_terms=n_terms) self.nparam = 3 @@ -1031,8 +1024,8 @@ def step(self, p: pstAL, dt: Optional[float] = 1.0, cutoff: Optional[float] = No h = 0 for n in range(self.n_terms): h += (-1) ** n / (2 * n + 1) ** 3 * \ - np.cos((2 * n + 1) * np.pi * p[2]) * \ - np.exp(-(2 * n + 1) ** 2 * t / p[1]) + np.cos((2 * n + 1) * np.pi * p[2]) * \ + np.exp(-(2 * n + 1) ** 2 * t / p[1]) s = p[0] * (1 - (8 / (np.pi ** 3 * (1 / 4 - p[2] ** 2)) * h)) return s @@ -1069,7 +1062,6 @@ class Spline(RfuncBase): """ _name = "Spline" - def __init__(self, kind: Optional[str] = 'quadratic', t: Optional[list] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]): RfuncBase.__init__(self, kind=kind, t=t) diff --git a/pastas/solver.py b/pastas/solver.py index e2159edc7..c842f62ed 100644 --- a/pastas/solver.py +++ b/pastas/solver.py @@ -17,7 +17,7 @@ from scipy.linalg import svd from scipy.optimize import least_squares -from pastas.typeh import Type, Optional, Tuple, pstAL, pstMl, pstCB, pstFu +from pastas.typeh import Type, Optional, Tuple, Union, pstAL, pstMl, pstCB, pstFu logger = getLogger(__name__) diff --git a/pastas/stats/dutch.py b/pastas/stats/dutch.py index 755475264..9a95d86db 100644 --- a/pastas/stats/dutch.py +++ b/pastas/stats/dutch.py @@ -355,8 +355,8 @@ def mean_all(s, min_n_meas): # Helper functions -def _mean_spring(series: Type[Series], min_n_meas: int) -> float: - """Internal method to determine mean of timeseries values in spring. +def _get_spring(series: Type[Series], min_n_meas: int) -> float: + """Internal method to get values of timeseries values in spring. Part of year aggregator function for gvg method. diff --git a/pastas/stats/signatures.py b/pastas/stats/signatures.py index 498e1d0fb..60b4b8f58 100644 --- a/pastas/stats/signatures.py +++ b/pastas/stats/signatures.py @@ -1,7 +1,7 @@ """This module contains methods to compute the groundwater signatures.""" import pandas as pd -from pandas import NA, Timedelta, DatetimeIndex, cut, Series -from numpy import diff, sqrt, log, arange +from pandas import Timedelta, DatetimeIndex, cut, Series +from numpy import diff, sqrt, log, arange, nan import pastas as ps from scipy.stats import linregress diff --git a/pastas/stressmodels.py b/pastas/stressmodels.py index bd3735485..6f02a92e7 100644 --- a/pastas/stressmodels.py +++ b/pastas/stressmodels.py @@ -49,7 +49,7 @@ class StressModelBase: """ _name = "StressModelBase" - def __init__(self, name: str, tmin: pstTm, tmax: pstTm, rfunc: Optional[pstRF] = None: up: Optional[bool] = True, meanstress: Optional[float] = 1.0, cutoff: Optional[float] = 0.999): + def __init__(self, name: str, tmin: pstTm, tmax: pstTm, rfunc: Optional[pstRF] = None, up: Optional[bool] = True, meanstress: Optional[float] = 1.0, cutoff: Optional[float] = 0.999): self.name = validate_name(name) self.tmin = tmin self.tmax = tmax diff --git a/pastas/typeh.py b/pastas/typeh.py index 0a9055c05..d9fb977cb 100644 --- a/pastas/typeh.py +++ b/pastas/typeh.py @@ -34,4 +34,4 @@ pstCB = TypeVar("pstCB", bound=Union[SolveTimer, TrackSolve]) # Callback pstFu = TypeVar("pstFu") # Function (e.g. Objective Function) pstRF = TypeVar("pstRF", bound=RfuncBase) # rFunc Base -pstAL = TypeVar("pstAL", bound=ArrayLike) # Array Like (NumPy based) +pstAL = TypeVar("pstAL", bound=Type[ArrayLike]) # Array Like (NumPy based)