Skip to content

Commit 21f4292

Browse files
Merge pull request #83 from sgfsweden/dev
Release v0.3.2
2 parents 2ad30bf + ad68b23 commit 21f4292

File tree

17 files changed

+948
-503
lines changed

17 files changed

+948
-503
lines changed

docs/conf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
project = "gwrefpy"
1515
copyright = ""
1616
author = ""
17-
release = "0.3.1"
17+
release = "0.3.2"
1818

1919
# -- General configuration ---------------------------------------------------
2020
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -31,6 +31,11 @@
3131
"myst_nb",
3232
]
3333

34+
myst_enable_extensions = [
35+
"amsmath",
36+
"dollarmath",
37+
]
38+
3439
templates_path = ["_templates"]
3540
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
3641

docs/user_guide/2_fitting_wells.ipynb

Lines changed: 319 additions & 300 deletions
Large diffs are not rendered by default.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
{
2+
"cells": [
3+
{
4+
"metadata": {},
5+
"cell_type": "markdown",
6+
"source": [
7+
"# Fitting Methods\n",
8+
"This notebook describes various methods available in the gwrefpy package for fitting observation and reference data.\n",
9+
"\n",
10+
"Currently supported fitting methods include:\n",
11+
"- Linear Regression\n",
12+
"- Nth order polynomial fitting\n",
13+
"- Chebyshev polynomial fitting"
14+
],
15+
"id": "c50ea0e738fe2d39"
16+
},
17+
{
18+
"cell_type": "code",
19+
"execution_count": null,
20+
"id": "initial_id",
21+
"metadata": {
22+
"collapsed": true
23+
},
24+
"outputs": [],
25+
"source": ""
26+
},
27+
{
28+
"metadata": {},
29+
"cell_type": "markdown",
30+
"source": [
31+
"# Linear Regression\n",
32+
"The linear regression fitting method fits a straight line to the data using the least squares method. It is suitable for data that exhibits a linear relationship.\n",
33+
"\n",
34+
"The equation for a linear regression is given by:\n",
35+
"\n",
36+
"$$y = a_0 + a_1x$$\n",
37+
"\n",
38+
"where $a_0$ and $a_1$ are the coefficients."
39+
],
40+
"id": "154554bb0b406c88"
41+
},
42+
{
43+
"metadata": {},
44+
"cell_type": "markdown",
45+
"source": [
46+
"# Nth Order Polynomial Fitting\n",
47+
"The Nth order polynomial fitting method fits a polynomial of degree N to the data. This method is useful when more degrees of freedom are needed to capture the relationship between the variables.\n",
48+
"\n",
49+
"The equation for a Nth order polynomial is given by:\n",
50+
"\n",
51+
"$$y = a_0 + a_1 x + a_2 x^2 + ... + a_N x^N$$\n",
52+
"\n",
53+
"where $a_0$, $a_1$, $...$, $a_N$ are the coefficients of the polynomial."
54+
],
55+
"id": "a226ea44aebc824f"
56+
},
57+
{
58+
"metadata": {},
59+
"cell_type": "markdown",
60+
"source": "",
61+
"id": "dbe8afaba89fa1c5"
62+
},
63+
{
64+
"metadata": {},
65+
"cell_type": "markdown",
66+
"source": [
67+
"# Chebyshev Polynomial Fitting\n",
68+
"The Chebyshev polynomial fitting method uses Chebyshev polynomials to fit the data. Chebyshev polynomials are orthogonal polynomials that can provide a good approximation for functions over a specific interval.\n",
69+
"\n",
70+
"The equation for a Chebyshev polynomial of degree N is given by:\n",
71+
"\n",
72+
"$$y = a_0T_0(x) + a_1T_1(x) + a_2T_2(x) + ... + a_NT_n(x)$$\n",
73+
"\n",
74+
"where $T_N(x)$ is the Chebyshev polynomial of degree $N$ and $a_0$, $a_1$, $...$, $a_N$ are the coefficients of the polynomial. The Chebyshev polynomials are defined recursively as:\n",
75+
"\n",
76+
"$$T_0(x) = 1$$\n",
77+
"\n",
78+
"$$T_1(x) = x$$\n",
79+
"\n",
80+
"$$T_{n+1}(x) = 2xT_n(x) - T_{n-1}(x)$$"
81+
],
82+
"id": "56956a578d0d429e"
83+
},
84+
{
85+
"metadata": {},
86+
"cell_type": "code",
87+
"outputs": [],
88+
"execution_count": null,
89+
"source": "",
90+
"id": "5c96914bfc2b31b8"
91+
}
92+
],
93+
"metadata": {
94+
"kernelspec": {
95+
"display_name": "Python 3",
96+
"language": "python",
97+
"name": "python3"
98+
},
99+
"language_info": {
100+
"codemirror_mode": {
101+
"name": "ipython",
102+
"version": 2
103+
},
104+
"file_extension": ".py",
105+
"mimetype": "text/x-python",
106+
"name": "python",
107+
"nbconvert_exporter": "python",
108+
"pygments_lexer": "ipython2",
109+
"version": "2.7.6"
110+
}
111+
},
112+
"nbformat": 4,
113+
"nbformat_minor": 5
114+
}

docs/user_guide/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ If you already have the package installed, make sure to update it to the latest
3333
3_time_offsets.ipynb
3434
4_plotting.ipynb
3535
5_io.ipynb
36-
6_logging.ipynb
36+
6_logging.ipynb
37+
7_fitting_methods.ipynb

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "gwrefpy"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
description = "A python implementation of the Akvifär reference method for detecting deviations in groundwater level time series."
55
readme = "README.md"
66
license = "MIT"

src/gwrefpy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__name__ = "gwrefpy"
2-
__version__ = "0.3.1"
2+
__version__ = "0.3.2"
33

44
from .constants import print_constants
55
from .methods.timeseries import analyze_offsets

src/gwrefpy/fitbase.py

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
import pandas as pd
55

6-
from .fitresults import FitResultData, LinRegResult, NPolyFitResult
6+
from .fitresults import ChebyshevFitResult, FitResultData, LinRegResult, NPolyFitResult
7+
from .methods.chebyshev import chebyshevfit
78
from .methods.linregressfit import linregressfit
89
from .methods.npolyfit import npolyfit
910
from .well import Well
@@ -24,7 +25,9 @@ def fit(
2425
offset: pd.DateOffset | pd.Timedelta | str,
2526
aggregation: Literal["mean", "median", "min", "max"] = "mean",
2627
p: float = 0.95,
27-
method: Literal["linearregression", "npolyfit"] = "linearregression",
28+
method: Literal[
29+
"linearregression", "npolyfit", "chebyshev"
30+
] = "linearregression",
2831
tmin: pd.Timestamp | str | None = None,
2932
tmax: pd.Timestamp | str | None = None,
3033
report: bool = True,
@@ -51,9 +54,9 @@ def fit(
5154
equivalents (default is "mean").
5255
p : float, optional
5356
The confidence level for the fit (default is 0.95).
54-
method : Literal["linearregression", "npolyfit"]
55-
Method with which to perform regression. Currently only supports
56-
linear regression and N-th degree polynomial fit.
57+
method : Literal["linearregression", "npolyfit", "chebyshev"]
58+
Method with which to perform regression. Currently supports
59+
linear regression, N-th degree polynomial fit, and Chebyshev polynomial fit.
5760
tmin: pd.Timestamp | str | None = None
5861
Minimum time for calibration period.
5962
tmax: pd.Timestamp | str | None = None
@@ -63,7 +66,7 @@ def fit(
6366
**kwargs
6467
Additional keyword arguments to pass to the fitting method.
6568
For example, you can use `degree` (default is 4) when using the `npolyfit`
66-
method.
69+
or `chebyshev` methods.
6770
6871
Returns
6972
-------
@@ -133,7 +136,9 @@ def _fit(
133136
ref_well: Well,
134137
offset: pd.DateOffset | pd.Timedelta | str,
135138
p: float = 0.95,
136-
method: Literal["linearregression", "npolyfit"] = "linearregression",
139+
method: Literal[
140+
"linearregression", "npolyfit", "chebyshev"
141+
] = "linearregression",
137142
tmin: pd.Timestamp | str | None = None,
138143
tmax: pd.Timestamp | str | None = None,
139144
aggregation: Literal["mean", "median", "min", "max"] = "mean",
@@ -159,6 +164,12 @@ def _fit(
159164
fit = npolyfit(
160165
obs_well, ref_well, offset, degree, tmin, tmax, p, aggregation
161166
)
167+
elif method == "chebyshev":
168+
logger.debug("Using Chebyshev polynomial fit method for fitting.")
169+
degree = kwargs.get("degree", 4)
170+
fit = chebyshevfit(
171+
obs_well, ref_well, offset, degree, tmin, tmax, p, aggregation
172+
)
162173
if fit is None:
163174
logger.error(f"Fitting method '{method}' is not implemented.")
164175
raise NotImplementedError(f"Fitting method '{method}' is not implemented.")
@@ -171,7 +182,9 @@ def best_fit(
171182
self,
172183
obs_well: str | Well,
173184
ref_wells: list[str | Well] | None = None,
174-
method: Literal["linearregression"] = "linearregression",
185+
method: Literal[
186+
"linearregression", "npolyfit", "chebyshev"
187+
] = "linearregression",
175188
**kwargs,
176189
) -> FitResultData:
177190
"""
@@ -184,7 +197,7 @@ def best_fit(
184197
ref_wells : Well or list of Well or None, optional
185198
The reference wells to test. If None, all reference wells in the
186199
model will be used (default is None).
187-
method : Literal["linearregression"]
200+
method : Literal["linearregression", "npolyfit", "chebyshev"]
188201
Method with which to perform regression. Currently only supports
189202
linear regression.
190203
**kwargs
@@ -202,7 +215,9 @@ def _best_fit(
202215
self,
203216
obs_well: str | Well,
204217
ref_wells: list[str | Well] | None = None,
205-
method: Literal["linearregression"] = "linearregression",
218+
method: Literal[
219+
"linearregression", "npolyfit", "chebyshev"
220+
] = "linearregression",
206221
**kwargs,
207222
) -> FitResultData:
208223
"""
@@ -215,7 +230,7 @@ def _best_fit(
215230
ref_wells : Well or list of Well or None, optional
216231
The reference wells to test. If None, all reference wells in the
217232
model will be used (default is None).
218-
method : Literal["linearregression"]
233+
method : Literal["linearregression", "npolyfit", "chebyshev"]
219234
Method with which to perform regression. Currently only supports
220235
linear regression.
221236
**kwargs
@@ -289,7 +304,8 @@ def get_fits(
289304
The well to check.
290305
method : str | None, optional
291306
The fitting method to filter by (default is None, which returns all
292-
fits involving the well). Options are "linearregression" and "npolyfit".
307+
fits involving the well). Options are "linearregression", "npolyfit", and
308+
"chebyshev".
293309
294310
Returns
295311
-------
@@ -315,7 +331,12 @@ def get_fits(
315331
fit_list = [
316332
fit for fit in fit_list if isinstance(fit.fit_method, NPolyFitResult)
317333
]
318-
334+
elif method == "chebyshev":
335+
fit_list = [
336+
fit
337+
for fit in fit_list
338+
if isinstance(fit.fit_method, ChebyshevFitResult)
339+
]
319340
return (
320341
fit_list
321342
if len(fit_list) > 1

0 commit comments

Comments
 (0)