Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix for Problem adding LinearTrend #675 #676

Merged
merged 4 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 29 additions & 25 deletions pastas/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from pastas.modelstats import Statistics
from pastas.noisemodels import NoiseModel
from pastas.plotting.modelplots import Plotting, _table_formatter_stderr
from pastas.rfunc import HantushWellModel
from pastas.solver import LeastSquares
from pastas.stressmodels import Constant
from pastas.timeseries import TimeSeries
Expand All @@ -44,6 +45,8 @@
from pastas.utils import validate_name
from pastas.version import __version__

logger = getLogger(__name__)


class Model:
"""Class that initiates a Pastas time series model.
Expand Down Expand Up @@ -93,8 +96,6 @@ def __init__(
metadata: Optional[dict] = None,
freq: str = "D",
) -> None:
self.logger = getLogger(__name__)

# Construct the different model components
self.oseries = TimeSeries(oseries, settings="oseries", metadata=metadata)

Expand Down Expand Up @@ -211,13 +212,13 @@ def add_stressmodel(
for sm in stressmodel:
self.add_stressmodel(sm)
elif (stressmodel.name in self.stressmodels.keys()) and not replace:
self.logger.error(
logger.error(
"The name for the stressmodel you are trying to add already exists "
"for this model. Select another name."
)
else:
if stressmodel.name in self.stressmodels.keys():
self.logger.warning(
logger.warning(
"The name for the stressmodel you are trying to add already "
"exists for this model. The stressmodel is replaced."
)
Expand All @@ -229,7 +230,7 @@ def add_stressmodel(
if (stressmodel.tmin > self.oseries.series.index.max()) or (
stressmodel.tmax < self.oseries.series.index.min()
):
self.logger.warning(
logger.warning(
"The stress of the stressmodel has no overlap with ml.oseries."
)
self._check_stressmodel_compatibility()
Expand Down Expand Up @@ -318,23 +319,23 @@ def del_stressmodel(self, name: str):
def del_constant(self) -> None:
"""Method to safely delete the Constant from the Model."""
if self.constant is None:
self.logger.warning("No constant is present in this model.")
logger.warning("No constant is present in this model.")
else:
self.constant = None
self.parameters = self.get_init_parameters(initial=False)

def del_transform(self) -> None:
"""Method to safely delete the transform from the Model."""
if self.transform is None:
self.logger.warning("No transform is present in this model.")
logger.warning("No transform is present in this model.")
else:
self.transform = None
self.parameters = self.get_init_parameters(initial=False)

def del_noisemodel(self) -> None:
"""Method to safely delete the noise model from the Model."""
if self.noisemodel is None:
self.logger.warning("No noisemodel is present in this model.")
logger.warning("No noisemodel is present in this model.")
else:
self.noisemodel = None
self.parameters = self.get_init_parameters(initial=False)
Expand Down Expand Up @@ -436,7 +437,7 @@ def simulate(
"are provided for each stress model "
"(e.g. `ps.StressModel(stress, settings='prec')`!"
)
self.logger.error(msg)
logger.error(msg)
raise ValueError(msg)

sim.name = "Simulation"
Expand Down Expand Up @@ -492,7 +493,7 @@ def residuals(
if self.interpolate_simulation is None:
if oseries_calib.index.difference(sim.index).size != 0:
self.interpolate_simulation = True
self.logger.info(
logger.info(
"There are observations between the simulation time steps. Linear "
"interpolation between simulated values is used."
)
Expand All @@ -510,7 +511,7 @@ def residuals(

if res.hasnans:
res = res.dropna()
self.logger.warning("Nan-values were removed from the residuals.")
logger.warning("Nan-values were removed from the residuals.")

if self.normalize_residuals:
res = res.subtract(res.values.mean())
Expand Down Expand Up @@ -563,7 +564,7 @@ def noise(
This method returns None if no noise model is present in the model.
"""
if self.noisemodel is None or self.settings["noise"] is False:
self.logger.error(
logger.error(
"Noise cannot be calculated if there is no noisemodel present or is "
"not used during parameter estimation."
)
Expand Down Expand Up @@ -688,7 +689,7 @@ def initialize(
if noise is None and self.noisemodel:
noise = True
elif noise is True and self.noisemodel is None:
self.logger.warning(
logger.warning(
"Warning, solving with noise=True while no noisemodel is present. "
"noise set to False."
)
Expand Down Expand Up @@ -839,7 +840,7 @@ def solve(
noise=self.settings["noise"], weights=weights, **kwargs
)
if not success:
self.logger.warning("Model parameters could not be estimated well.")
logger.warning("Model parameters could not be estimated well.")

if self.settings["fit_constant"] is False:
# Determine the residuals and set the constant to their mean
Expand All @@ -865,7 +866,7 @@ def fit(self):
"Attribute 'fit' is deprecated and will be removed in a future version. "
"Use 'solver' instead."
)
self.logger.warning(msg)
logger.warning(msg)

return self.solver

Expand Down Expand Up @@ -915,7 +916,7 @@ def set_parameter(
"""
if name not in self.parameters.index:
msg = "parameter %s is not present in the model"
self.logger.error(msg, name)
logger.error(msg, name)
raise KeyError(msg, name)

# Because either of the following is not necessarily present
Expand Down Expand Up @@ -989,7 +990,7 @@ def _get_time_offset(self, freq: str) -> Timedelta:
time_offsets.add(_get_time_offset(t[mask][0], freq))
if len(time_offsets) > 1:
msg = "The time-offset with the frequency is not the same for all stresses."
self.logger.error(msg)
logger.error(msg)
raise (Exception(msg))
if len(time_offsets) == 1:
return next(iter(time_offsets))
Expand Down Expand Up @@ -1238,9 +1239,7 @@ def get_parameters(self, name: Optional[str] = None) -> ArrayLike:
p = self.parameters

if p.optimal.hasnans:
self.logger.warning(
"Model is not optimized yet, initial parameters are used."
)
logger.warning("Model is not optimized yet, initial parameters are used.")
parameters = p.initial
else:
parameters = p.optimal
Expand Down Expand Up @@ -1494,7 +1493,7 @@ def _get_response(
Pandas.Series with the response, None if not present.
"""
if self.stressmodels[name].rfunc is None:
self.logger.warning("Stressmodel %s has no rfunc.", name)
logger.warning("Stressmodel %s has no rfunc.", name)
return None
else:
block_or_step = getattr(self.stressmodels[name].rfunc, block_or_step)
Expand Down Expand Up @@ -1629,12 +1628,12 @@ def get_response_tmax(
to a recharge pulse has taken place.
"""
if self.stressmodels[name].rfunc is None:
self.logger.warning("Stressmodel %s has no rfunc", name)
logger.warning("Stressmodel %s has no rfunc", name)
return None
else:
if p is None:
p = self.get_parameters(name)
if self.stressmodels[name].rfunc._name == "HantushWellModel":
if isinstance(self.stressmodels[name].rfunc, HantushWellModel):
kwargs = {"warn": warn}
else:
kwargs = {}
Expand Down Expand Up @@ -1907,14 +1906,19 @@ def _check_response_tmax(self, cutoff: Optional[float] = None) -> DataFrame:

len_oseries_calib = (self.settings["tmax"] - self.settings["tmin"]).days

# only check stressmodels with a response function
sm_names = [
key for key, item in self.stressmodels.items() if item.rfunc is not None
]

check = DataFrame(
index=self.stressmodels.keys(),
index=sm_names,
columns=["len_oseries_calib", "response_tmax", "check_ok"],
)
check["len_oseries_calib"] = len_oseries_calib

for sm_name in self.stressmodels:
if self.stressmodels[sm_name].rfunc._name == "HantushWellModel":
if isinstance(self.stressmodels[sm_name].rfunc, HantushWellModel):
kwargs = {"warn": False}
else:
kwargs = {}
Expand Down
5 changes: 3 additions & 2 deletions pastas/plotting/modelcompare.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pandas import DataFrame, concat

from pastas.plotting.plotutil import _table_formatter_params, share_xaxes, share_yaxes
from pastas.rfunc import HantushWellModel
from pastas.stats.core import acf
from pastas.typing import Axes, Model

Expand Down Expand Up @@ -574,7 +575,7 @@ def plot_response(
if response == "step":
kwargs = {}
if ml.stressmodels[smn].rfunc is not None:
if ml.stressmodels[smn].rfunc._name == "HantushWellModel":
if isinstance(ml.stressmodels[smn].rfunc, HantushWellModel):
kwargs = {"warn": False}
step = ml.get_step_response(smn, add_0=True, **kwargs)
if step is None:
Expand All @@ -595,7 +596,7 @@ def plot_response(
elif response == "block":
kwargs = {}
if ml.stressmodels[smn].rfunc is not None:
if ml.stressmodels[smn].rfunc._name == "HantushWellModel":
if isinstance(ml.stressmodels[smn].rfunc, HantushWellModel):
kwargs = {"warn": False}
block = ml.get_block_response(smn, **kwargs)
if block is None:
Expand Down
3 changes: 2 additions & 1 deletion pastas/plotting/modelplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
_table_formatter_params,
_table_formatter_stderr,
)
from pastas.rfunc import HantushWellModel
from pastas.typing import Axes, Figure, Model, TimestampType

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -267,7 +268,7 @@ def results(
# plot the step response
rkwargs = {}
if self.ml.stressmodels[sm_name].rfunc is not None:
if self.ml.stressmodels[sm_name].rfunc._name == "HantushWellModel":
if isinstance(self.ml.stressmodels[sm_name].rfunc, HantushWellModel):
rkwargs = {"warn": False}
response = self.ml._get_response(
block_or_step=block_or_step, name=sm_name, add_0=True, **rkwargs
Expand Down