diff --git a/README.md b/README.md index f245673..7a41dc1 100644 --- a/README.md +++ b/README.md @@ -67,52 +67,53 @@ This will install python-tide and all its dependencies. ### Quick example + ```python import pandas as pd - from corrai.base.parameter import Parameter - from corrai.sensitivity import SobolSanalysis, MorrisSanalysis - from corrai.base.model import Ishigami - - SIMULATION_OPTIONS = { - "start": "2009-01-01 00:00:00", - "end": "2009-01-01 05:00:00", - "timestep": "h", - } - - PARAMETER_LIST = [ - Parameter("par_x1", (-3.14159265359, 3.14159265359), model_property="x1"), - Parameter("par_x2", (-3.14159265359, 3.14159265359), model_property="x2"), - Parameter("par_x3", (-3.14159265359, 3.14159265359), model_property="x3"), - ] - - # Configure a Sobol sensitivity analysis - sobol = SobolSanalysis( - parameters=PARAMETER_LIST, - model=Ishigami(), - simulation_options=SIMULATION_OPTIONS, - ) - - # Draw sample, and run simulations - sobol.add_sample(15**2, simulate=True, n_cpu=1, calc_second_order=True) - - # Corrai works for models that returns time series - # Ishigami model here will return the same value for the given parameters - # from START to END at 1h timestep - sobol.analyze('res', method="mean")["mean_res"] - - # Default aggregation method is mean value of the timeseries - sobol.plot_bar('res') - - # Display 2nd order matrix for parameters interaction - sobol.plot_s2_matrix('res') - - # Display mean output values of the sample as hist - sobol.sampler.sample.plot_hist('res') - - # Compute dynamic sensitivity analisys at plot - # Obviously, in this example indexes value do not vary - sobol.plot_dynamic_metric('res', sensitivity_metric="ST", freq="h") +from corrai.base.parameter import Parameter +from corrai.sensitivity import SobolSanalysis, MorrisSanalysis +from corrai.base.model import IshigamiDynamic + +SIMULATION_OPTIONS = { + "start": "2009-01-01 00:00:00", + "end": "2009-01-01 05:00:00", + "timestep": "h", +} + +PARAMETER_LIST = [ + Parameter("par_x1", (-3.14159265359, 3.14159265359), model_property="x1"), + Parameter("par_x2", (-3.14159265359, 3.14159265359), model_property="x2"), + Parameter("par_x3", (-3.14159265359, 3.14159265359), model_property="x3"), +] + +# Configure a Sobol sensitivity analysis +sobol = SobolSanalysis( + parameters=PARAMETER_LIST, + model=IshigamiDynamic(), + simulation_options=SIMULATION_OPTIONS, +) + +# Draw sample, and run simulations +sobol.add_sample(15 ** 2, simulate=True, n_cpu=1, calc_second_order=True) + +# Corrai works for models that returns time series +# Ishigami model here will return the same value for the given parameters +# from START to END at 1h timestep +sobol.analyze('res', method="mean")["mean_res"] + +# Default aggregation method is mean value of the timeseries +sobol.plot_bar('res') + +# Display 2nd order matrix for parameters interaction +sobol.plot_s2_matrix('res') + +# Display mean output values of the sample as hist +sobol.sampler.sample.plot_hist('res') + +# Compute dynamic sensitivity analisys at plot +# Obviously, in this example indexes value do not vary +sobol.plot_dynamic_metric('res', sensitivity_metric="ST", freq="h") ``` ### Sponsors diff --git a/corrai/base/model.py b/corrai/base/model.py index a5a9fbf..7638a5f 100644 --- a/corrai/base/model.py +++ b/corrai/base/model.py @@ -1,3 +1,5 @@ +from typing import Union + import pandas as pd import numpy as np @@ -18,6 +20,12 @@ class Model(ABC): Subclasses must implement the :meth:`simulate` method. + Parameters + ---------- + is_dynamic : bool, default=True + Indicates if the model returns time dependant results as DataFrame with + DatetimeIndex, or is static and returns a Series of values + Methods ------- get_property_from_param(parameter_value_pairs) @@ -31,9 +39,12 @@ class Model(ABC): Retrieve current values of given model properties. Must be implemented in subclasses if relative parameters are used. save(file_path) - Persist the model state or parameters to disk. Optional. + Persists the model state or parameters to disk. Optional. """ + def __init__(self, is_dynamic: bool = True): + self.is_dynamic = is_dynamic + def get_property_from_param( self, parameter_value_pairs: list[tuple[Parameter, str | int | float]], @@ -79,7 +90,7 @@ def simulate( property_dict: dict[str, str | int | float] = None, simulation_options: dict = None, **simulation_kwargs, - ) -> pd.DataFrame: + ) -> pd.DataFrame | pd.Series: """ Run a simulation for given properties and options. @@ -108,7 +119,7 @@ def simulate_parameter( parameter_value_pairs: list[tuple[Parameter, str | int | float]], simulation_options: dict = None, simulation_kwargs: dict = None, - ) -> pd.DataFrame: + ) -> Union[pd.DataFrame, pd.Series]: """ Simulate the model given a set of parameter-value pairs. @@ -179,7 +190,7 @@ def save(self, file_path: Path): raise NotImplementedError("No save method was defined for this model") -class Ishigami(Model): +class IshigamiDynamic(Model): """ Example implementation of the Ishigami function. @@ -202,6 +213,7 @@ class Ishigami(Model): """ def __init__(self): + super().__init__(is_dynamic=True) self.x1 = 1 self.x2 = 2 self.x3 = 3 @@ -236,3 +248,109 @@ def simulate( freq=simulation_options["timestep"], ), ) + + +class Ishigami(Model): + """ + Example implementation of the Ishigami function. + + The Ishigami function is a standard benchmark for sensitivity analysis: + f(x) = sin(x1) + 7 sin^2(x2) + 0.1 x3^4 sin(x1) + + Attributes + ---------- + x1, x2, x3 : float + Model parameters controlling the output. + + Methods + ------- + get_property_values(property_list) + Retrieve current values of x1, x2, x3. + set_property_values(property_dict) + Set properties from a dictionary. + simulate(property_dict, simulation_options, simulation_kwargs) + Evaluate the Ishigami function and return as a Series. + """ + + def __init__(self): + super().__init__(is_dynamic=False) + self.x1 = 1 + self.x2 = 2 + self.x3 = 3 + + def get_property_values(self, property_list: list): + return [getattr(self, name) for name in property_list] + + def set_property_values(self, property_dict: dict): + for prop, val in property_dict.items(): + setattr(self, prop, val) + + def simulate( + self, + property_dict: dict[str, str | int | float] = None, + simulation_options: dict = None, + simulation_kwargs: dict = None, + ) -> pd.Series: + if property_dict is not None: + self.set_property_values(property_dict) + + res = ( + np.sin(self.x1) + + 7.0 * np.power(np.sin(self.x2), 2) + + 0.1 * np.power(self.x3, 4) * np.sin(self.x1) + ) + + return pd.Series({"res": res}) + + +class PymodelDynamic(Model): + def __init__(self): + super().__init__(is_dynamic=True) + self.prop_1 = 1 + self.prop_2 = 2 + self.prop_3 = 3 + + def get_property_values(self, property_list: list): + return [getattr(self, name) for name in property_list] + + def simulate( + self, + property_dict: dict[str, str | int | float] = None, + simulation_options: dict = None, + **simulation_kwargs, + ) -> pd.DataFrame: + if property_dict is not None: + for prop, val in property_dict.items(): + setattr(self, prop, val) + + return pd.DataFrame( + {"res": [self.prop_1 * self.prop_2 + self.prop_3]}, + index=pd.date_range( + simulation_options["start"], + simulation_options["end"], + freq=simulation_options["timestep"], + ), + ) + + +class PymodelStatic(Model): + def __init__(self): + super().__init__(is_dynamic=False) + self.prop_1 = 1 + self.prop_2 = 2 + self.prop_3 = 3 + + def get_property_values(self, property_list: list): + return [getattr(self, name) for name in property_list] + + def simulate( + self, + property_dict: dict[str, str | int | float] = None, + simulation_options: dict = None, + **simulation_kwargs, + ) -> pd.Series: + if property_dict is not None: + for prop, val in property_dict.items(): + setattr(self, prop, val) + + return pd.Series({"res": self.prop_1 * self.prop_2 + self.prop_3}) diff --git a/corrai/fmu.py b/corrai/fmu.py index 2a22883..1c994a2 100644 --- a/corrai/fmu.py +++ b/corrai/fmu.py @@ -266,6 +266,7 @@ def __init__( output_list: list[str] = None, boundary_table_name: str | None = None, ): + super().__init__(is_dynamic=True) fmu_path = Path(fmu_path) if isinstance(fmu_path, str) else fmu_path if not fmu_path.exists() or not fmu_path.is_file(): raise FileNotFoundError(f"FMU file not found at {fmu_path}") diff --git a/corrai/sampling.py b/corrai/sampling.py index 7b3395e..b62d16b 100644 --- a/corrai/sampling.py +++ b/corrai/sampling.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass, field from functools import wraps +from typing import Union import numpy as np import pandas as pd @@ -97,6 +98,8 @@ class Sample: simulation results. It supports indexing, aggregation, plotting, and integration with sampling strategies. + Handle both dynamic and static models. + Parameters ---------- parameters : list of Parameter @@ -106,6 +109,9 @@ class Sample: ---------- parameters : list of Parameter Parameters associated with this sample. + is_dynamic : Bool default True + Specify if stored results are timeeries in a DataFrame for dynamic models + or a Series of float for static models values : ndarray of shape (n_samples, n_parameters) Numerical values of the sampled parameters. results : Series of DataFrames @@ -114,6 +120,7 @@ class Sample: """ parameters: list[Parameter] + is_dynamic: bool = True values: pd.DataFrame = field(init=False) results: pd.Series = field(default_factory=lambda: pd.Series(dtype=object)) @@ -237,7 +244,9 @@ def get_dimension_less_values( intervals = self.get_parameters_intervals() return (values - intervals[:, 0]) / (intervals[:, 1] - intervals[:, 0]) - def add_samples(self, values: np.ndarray, results: list[pd.DataFrame] = None): + def add_samples( + self, values: np.ndarray, results: list[Union[pd.DataFrame, pd.Series]] = None + ): """ Add new samples and optionally their results. @@ -288,6 +297,8 @@ def get_aggregated_time_series( If `freq` is provided, the aggregation is done over time bins, producing a table of simulation runs versus time periods. + Only works for dynamic models + Parameters ---------- indicator : str @@ -379,6 +390,8 @@ def get_aggregated_time_series( 1 2.0 3.0 """ + if not self.is_dynamic: + raise ValueError("Cannot perform time aggregation on static sample") return aggregate_time_series( self.results, @@ -390,6 +403,11 @@ def get_aggregated_time_series( prefix, ) + def get_static_results_as_df(self): + if self.is_dynamic: + raise ValueError("Cannot map results to a DataFrame with a dynamic Sample") + return pd.DataFrame(self.results.to_list(), index=self.results.index) + def plot_hist( self, indicator: str, @@ -439,18 +457,24 @@ def plot_hist( go.Figure Plotly histogram figure. """ - res = self.get_aggregated_time_series( - indicator, - method, - agg_method_kwarg, - reference_time_series, - freq=None, - prefix=method, - ) + if self.is_dynamic: + res = self.get_aggregated_time_series( + indicator, + method, + agg_method_kwarg, + reference_time_series, + freq=None, + prefix=method, + ) + hist_label = f"{method} {indicator}" + + else: + res = self.get_static_results_as_df()[[indicator]] + hist_label = indicator fig = ff.create_distplot( [res.squeeze().to_numpy()], - [f"{method}_{indicator}"], + [hist_label], bin_size=(res.max() - res.min()) / bins, colors=[colors], show_rug=show_rug, @@ -471,12 +495,10 @@ def plot_hist( # Make sure it spans the full y-axis range fig.update_yaxes(range=[0, None]) # auto from 0 to max - title = ( - f"Sample distribution of {method} {indicator}" if title is None else title - ) + title = f"Sample distribution of {hist_label}" if title is None else title fig.update_layout( title=title, - xaxis_title=f"{method} {indicator} {unit}", + xaxis_title=f"{hist_label} {unit}", ) return fig @@ -500,6 +522,8 @@ def plot_sample( either as a scatter plot of all samples or as an aggregated area with min–max envelope, median, and quantile bands. + Only works for dynamic models + Parameters ---------- indicator : str, optional @@ -539,6 +563,8 @@ def plot_sample( >>> fig = plot_sample(results, reference_timeseries=ref, type_graph="scatter") >>> fig.show() """ + if not self.is_dynamic: + raise ValueError("Cannot plot_sample a static sample") if self.results.empty: raise ValueError("`results` is empty. Simulate samples first.") @@ -716,7 +742,7 @@ def __init__( {} if simulation_options is None else simulation_options ) self.model = model - self.sample = Sample(parameters) + self.sample = Sample(parameters, is_dynamic=model.is_dynamic) @property def parameters(self): diff --git a/corrai/sensitivity.py b/corrai/sensitivity.py index beeea05..a46ad0b 100644 --- a/corrai/sensitivity.py +++ b/corrai/sensitivity.py @@ -1,3 +1,4 @@ +import warnings from abc import ABC, abstractmethod from functools import wraps @@ -162,14 +163,24 @@ def analyze( - If `x_needed=True`, the analyser will receive both `X` and `Y`. - The analyser is typically an object from SALib. """ - agg_result = self.sampler.sample.get_aggregated_time_series( - indicator, - method, - agg_method_kwarg, - reference_time_series, - freq, - prefix=method, - ) + if self.sampler.sample.is_dynamic: + agg_result = self.sampler.sample.get_aggregated_time_series( + indicator, + method, + agg_method_kwarg, + reference_time_series, + freq, + prefix=method, + ) + else: + if method or agg_method_kwarg: + warnings.warn( + "'method' or 'agg_method_kwarg' was provided but Model is static." + " Arguments will be ignored" + ) + if freq: + raise ValueError("freq was specified with a static model") + agg_result = self.sampler.sample.get_static_results_as_df()[[indicator]] if self.x_needed: analyse_kwargs["X"] = self.sampler.sample.get_dimension_less_values().values @@ -275,6 +286,11 @@ def salib_plot_dynamic_metric( go.Figure Stacked or line plot of sensitivity metrics over time. """ + if not self.sampler.sample.is_dynamic: + raise ValueError( + "Cannot perform dynamic sensitivity analysis on static sample" + ) + title = ( f"{sensitivity_method_name} dynamic {sensitivity_metric} {method} {indicator}" if title is None @@ -413,7 +429,6 @@ def salib_plot_matrix( indicator: str, sensitivity_method_name: str, method: str = "mean", - unit: str = "", reference_time_series: pd.Series = None, agg_method_kwarg: dict = None, title: str = None, @@ -581,11 +596,8 @@ def plot_dynamic_metric( def plot_s2_matrix( self, indicator: str = "res", - sensitivity_metric: str = "S2", method: str = "mean", reference_time_series: pd.Series = None, - calc_second_order: bool = True, - unit: str = "", agg_method_kwarg: dict = None, title: str = None, **analyse_kwargs, @@ -594,11 +606,9 @@ def plot_s2_matrix( indicator=indicator, sensitivity_method_name="Sobol", method=method, - unit=unit, reference_time_series=reference_time_series, agg_method_kwarg=agg_method_kwarg, title=title, - calc_second_order=calc_second_order, **analyse_kwargs, ) diff --git a/tests/base/test_model.py b/tests/base/test_model.py index bcf136d..a7314de 100644 --- a/tests/base/test_model.py +++ b/tests/base/test_model.py @@ -1,5 +1,5 @@ from corrai.base.parameter import Parameter -from ..resources.pymodels import Pymodel +from corrai.base.model import PymodelDynamic PARAM_LIST = [ Parameter("par1", (0, 2), relabs="Absolute", model_property=("prop_1", "prop_2")), @@ -15,7 +15,7 @@ class TestModel: def test_pymodel(self): - mod = Pymodel() + mod = PymodelDynamic() res = mod.simulate(simulation_options=SIMULATION_OPTIONS) diff --git a/tests/base/test_simulate.py b/tests/base/test_simulate.py index b3d2b02..6fa96be 100644 --- a/tests/base/test_simulate.py +++ b/tests/base/test_simulate.py @@ -2,7 +2,7 @@ from corrai.base.parameter import Parameter from corrai.base.simulate import run_simulations -from corrai.base.model import Ishigami +from corrai.base.model import IshigamiDynamic SIMULATION_OPTIONS = { "start": "2009-01-01 00:00:00", @@ -24,7 +24,7 @@ class TestSimulate: def test_run_models_in_parallel(self): - model = Ishigami() + model = IshigamiDynamic() res = run_simulations(model, PARAMETER_PAIRS, SIMULATION_OPTIONS, n_cpu=1) diff --git a/tests/resources/pymodels.py b/tests/resources/pymodels.py deleted file mode 100644 index bbbd6ea..0000000 --- a/tests/resources/pymodels.py +++ /dev/null @@ -1,76 +0,0 @@ -from corrai.base.model import Model - -import pandas as pd -from pathlib import Path - - -class Pymodel(Model): - def __init__(self): - self.prop_1 = 1 - self.prop_2 = 2 - self.prop_3 = 3 - - def get_property_values(self, property_list: list): - return [getattr(self, name) for name in property_list] - - def simulate( - self, - property_dict: dict[str, str | int | float] = None, - simulation_options: dict = None, - **simulation_kwargs, - ) -> pd.DataFrame: - if property_dict is not None: - for prop, val in property_dict.items(): - setattr(self, prop, val) - - return pd.DataFrame( - {"res": [self.prop_1 * self.prop_2 + self.prop_3]}, - index=pd.date_range( - simulation_options["start"], - simulation_options["end"], - freq=simulation_options["timestep"], - ), - ) - - -class VariantModel(Model): - def __init__(self): - self.y1 = 1 - self.z1 = 2 - self.multiplier = 1 - - def simulate( - self, - property_dict: dict = None, - simulation_options: dict = None, - simulation_kwargs: dict = None, - ) -> pd.DataFrame: - if property_dict is None: - property_dict = {"x1": 1, "x2": 2} - - result = ( - self.y1 * property_dict["x1"] + self.z1 * property_dict["x2"] - ) * self.multiplier - - # Create a DataFrame with a single row - df = pd.DataFrame( - {"res": [result]}, - index=pd.date_range( - simulation_options["start"], - simulation_options["end"], - freq=simulation_options["timestep"], - ), - ) - - return df - - def save(self, file_path: Path): - """ - Save the current parameters of the model to a file. - - :param file_path: The file path where the parameters will be saved. - """ - with open(f"{file_path}", "w") as file: - file.write(f"y1={self.y1}\n") - file.write(f"z1={self.z1}\n") - file.write(f"multiplier={self.multiplier}\n") diff --git a/tests/test_fmu.py b/tests/test_fmu.py index e88b441..377c626 100644 --- a/tests/test_fmu.py +++ b/tests/test_fmu.py @@ -50,12 +50,9 @@ def test_results(self): ) ref = pd.DataFrame( - data=np.array([[401.0]]*6), + data=np.array([[401.0]] * 6), index=pd.date_range( - "2009-01-01 00:00:00", - "2009-01-01 05:00:00", - freq="1h", - name="time" + "2009-01-01 00:00:00", "2009-01-01 05:00:00", freq="1h", name="time" ), columns=["res.showNumber"], ) diff --git a/tests/test_sampling.py b/tests/test_sampling.py index 42a06b9..fceaf63 100644 --- a/tests/test_sampling.py +++ b/tests/test_sampling.py @@ -12,8 +12,7 @@ ) from corrai.base.math import aggregate_time_series -from corrai.base.model import Ishigami -from tests.resources.pymodels import Pymodel +from corrai.base.model import IshigamiDynamic, Ishigami, PymodelDynamic, PymodelStatic import pytest @@ -42,7 +41,8 @@ class TestSample: - def test_sample_functions(self): + def test_sample_methods(self): + # Dynamic sample sample = Sample(REAL_PARAM) assert sample.values.shape == (0, 3) pd.testing.assert_series_equal(sample.results, pd.Series()) @@ -125,6 +125,19 @@ def test_sample_functions(self): sample._validate() + # Static Sample + sample_static = Sample(REAL_PARAM, is_dynamic=False) + + sample_static.add_samples( + np.array([[1, 0.9, 10], [3, 0.85, 20]]), + [pd.Series(), pd.Series({"res": 2})], + ) + + pd.testing.assert_frame_equal( + sample_static.get_static_results_as_df(), + pd.DataFrame({"res": {0: np.nan, 1: 2.0}}), + ) + def test_plot_sample(self): t = pd.date_range("2025-01-01 00:00:00", periods=2, freq="h") df1 = pd.DataFrame({"res": [1.0, 2.0]}, index=t) @@ -224,9 +237,10 @@ def test_plot_sample(self): assert fig.data[-1].mode == "lines" def test_plot_hist(self): + # Dynamic sampler = LHSSampler( parameters=REAL_PARAM, - model=Pymodel(), + model=PymodelDynamic(), simulation_options=SIMULATION_OPTIONS, ) sampler.add_sample(3, 42, simulate=True) @@ -249,6 +263,32 @@ def test_plot_hist(self): hist = hist_traces[0] assert len(hist.x) == len(sampler.results) + # Static + sampler = LHSSampler( + parameters=ISHIGAMI_PARAMETERS, + model=Ishigami(), + simulation_options=SIMULATION_OPTIONS, + ) + + sampler.add_sample(3, 42) + + fig = sampler.sample.plot_hist( + indicator="res", + unit="J", + bins=10, + colors="orange", + reference_value=70, + show_rug=True, + ) + + assert isinstance(fig, go.Figure) + assert fig.layout.title.text == "Sample distribution of res" + + hist_traces = [tr for tr in fig.data if tr.type == "histogram"] + assert len(hist_traces) == 1 + hist = hist_traces[0] + assert len(hist.x) == len(sampler.results) + def test_plot_pcp(self): t = pd.date_range("2025-01-01 00:00:00", periods=2, freq="h") df1 = pd.DataFrame({"res": [1.0, 2.0]}, index=t) @@ -289,7 +329,7 @@ def test_plot_pcp(self): def test_plot_pcp_in_sampler(self): sampler = LHSSampler( parameters=REAL_PARAM, - model=Pymodel(), + model=PymodelDynamic(), simulation_options=SIMULATION_OPTIONS, ) sampler.add_sample(3, 42, simulate=True) @@ -301,9 +341,10 @@ def test_plot_pcp_in_sampler(self): assert len(fig.data) == 1 def test_lhs_sampler(self): + # Dynamic sampler = LHSSampler( parameters=REAL_PARAM, - model=Pymodel(), + model=PymodelDynamic(), simulation_options=SIMULATION_OPTIONS, ) sampler.add_sample(3, 42, False) @@ -385,10 +426,37 @@ def test_lhs_sampler(self): check_exact=False, ) + # Static + sampler = LHSSampler( + parameters=REAL_PARAM, + model=PymodelStatic(), + simulation_options=SIMULATION_OPTIONS, + ) + sampler.add_sample(3, 42) + np.testing.assert_allclose( + sampler.sample.values, + np.array( + [ + [6.9441, 1.0785, 70.7802], + [5.6356, 0.9393, 27.4968], + [0.0112, 0.8330, 61.6539], + ] + ), + rtol=0.01, + ) + + pd.testing.assert_frame_equal( + sampler.sample.get_static_results_as_df(), + pd.DataFrame({"res": {0: 85.759, 1: 38.084, 2: 61.672}}), + atol=0.01, + ) + + assert True + def test_morris_sampler(self): sampler = MorrisSampler( parameters=ISHIGAMI_PARAMETERS, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) @@ -408,7 +476,7 @@ def test_morris_sampler(self): def test_sobol_sampler(self): sampler = SobolSampler( parameters=ISHIGAMI_PARAMETERS, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) diff --git a/tests/test_sensitivity.py b/tests/test_sensitivity.py index 7f0cf91..36489f4 100644 --- a/tests/test_sensitivity.py +++ b/tests/test_sensitivity.py @@ -2,7 +2,7 @@ import pandas as pd from corrai.base.parameter import Parameter -from corrai.base.model import Ishigami +from corrai.base.model import IshigamiDynamic, Ishigami from corrai.sensitivity import ( SobolSanalysis, MorrisSanalysis, @@ -26,10 +26,43 @@ class TestSensitivity: def test_sanalysis_sobol_with_sobol_sampler(self): + # sobol_analysis = SobolSanalysis( + # parameters=PARAMETER_LIST, + # model=IshigamiDynamic(), + # simulation_options=SIMULATION_OPTIONS, + # ) + # + # sobol_analysis.add_sample(N=1000, n_cpu=1, calc_second_order=True, seed=42) + # res = sobol_analysis.analyze("res", calc_second_order=True, seed=42) + # + # np.testing.assert_almost_equal( + # res["mean_res"]["S1"], + # np.array([0.33080399, 0.44206835, 0.00946747]), + # ) + # + # res = sobol_analysis.analyze("res", freq="h", calc_second_order=True, seed=42) + # assert res.index.tolist() == [ + # pd.Timestamp("2009-01-01 00:00:00"), + # pd.Timestamp("2009-01-01 01:00:00"), + # pd.Timestamp("2009-01-01 02:00:00"), + # pd.Timestamp("2009-01-01 03:00:00"), + # pd.Timestamp("2009-01-01 04:00:00"), + # pd.Timestamp("2009-01-01 05:00:00"), + # ] + # + # sobol_analysis.plot_sample_hist( + # "res", bins=10, reference_value=10, reference_label="ref" + # ) + # + # np.testing.assert_almost_equal( + # res["2009-01-01 00:00:00"]["S1"], + # np.array([0.33080399, 0.44206835, 0.00946747]), + # decimal=3, + # ) + # sobol_analysis = SobolSanalysis( parameters=PARAMETER_LIST, model=Ishigami(), - simulation_options=SIMULATION_OPTIONS, ) sobol_analysis.add_sample(N=1000, n_cpu=1, calc_second_order=True, seed=42) @@ -40,30 +73,12 @@ def test_sanalysis_sobol_with_sobol_sampler(self): np.array([0.33080399, 0.44206835, 0.00946747]), ) - res = sobol_analysis.analyze("res", freq="h", calc_second_order=True, seed=42) - assert res.index.tolist() == [ - pd.Timestamp("2009-01-01 00:00:00"), - pd.Timestamp("2009-01-01 01:00:00"), - pd.Timestamp("2009-01-01 02:00:00"), - pd.Timestamp("2009-01-01 03:00:00"), - pd.Timestamp("2009-01-01 04:00:00"), - pd.Timestamp("2009-01-01 05:00:00"), - ] - - sobol_analysis.plot_sample_hist( - "res", bins=10, reference_value=10, reference_label="ref" - ) - - np.testing.assert_almost_equal( - res["2009-01-01 00:00:00"]["S1"], - np.array([0.33080399, 0.44206835, 0.00946747]), - decimal=3, - ) + assert True def test_sanalysis_morris(self): morris_analysis = MorrisSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) morris_analysis.add_sample(N=1000, n_cpu=1, seed=42) @@ -117,7 +132,7 @@ def test_sanalysis_morris(self): def test_sanalysis_fast(self): fast_analysis = FASTSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) # N = max(N, 4 * M**2 + 1) @@ -147,7 +162,7 @@ def test_sanalysis_fast(self): def test_sanalysis_rbdfast(self): rbdfast_analysis = RBDFASTSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) @@ -181,7 +196,7 @@ class TestPlots: def test_sobol_s2_matrix(self): sobol_analysis = SobolSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) sobol_analysis.add_sample(N=2**2, n_cpu=1, calc_second_order=True) @@ -193,12 +208,12 @@ def test_sobol_s2_matrix(self): def test_morris_plots(self): morris_analysis = MorrisSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, ) morris_analysis_2 = MorrisSanalysis( parameters=PARAMETER_LIST, - model=Ishigami(), + model=IshigamiDynamic(), simulation_options=SIMULATION_OPTIONS, )