Skip to content

Commit

Permalink
fix for Problem adding LinearTrend #675 (#676)
Browse files Browse the repository at this point in the history
Co-authored-by: Davíd Brakenhoff <d.brakenhoff@artesia-water.nl>
  • Loading branch information
OnnoEbbens and dbrakenhoff committed Jan 4, 2024
1 parent 0d7e816 commit 9c76689
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 28 deletions.
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

0 comments on commit 9c76689

Please sign in to comment.