def __init__(
        self,
        app,
        webviz_settings: WebvizSettings,
        ensembles: Optional[list] = None,
        csvfile_parameters: pathlib.Path = None,
        csvfile_smry: pathlib.Path = None,
        time_index: str = "monthly",
        column_keys: Optional[list] = None,
        drop_constants: bool = True,
    ):
        super().__init__()

        self.theme = webviz_settings.theme
        self.time_index = time_index
        self.column_keys = column_keys
        self.ensembles = ensembles
        self.csvfile_parameters = csvfile_parameters
        self.csvfile_smry = csvfile_smry

        if ensembles is not None:
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths={
                        ens:
                        webviz_settings.shared_settings["scratch_ensembles"]
                        [ens]
                        for ens in ensembles
                    },
                    time_index=self.time_index,
                    column_keys=self.column_keys,
                ))
            self.pmodel = ParametersModel(
                dataframe=self.emodel.load_parameters(),
                theme=self.theme,
                drop_constants=drop_constants,
            )
            self.vmodel = SimulationTimeSeriesModel(
                dataframe=self.emodel.get_or_load_smry_cached())

        elif self.csvfile_parameters is None:
            raise ValueError(
                "Either ensembles or csvfile_parameters must be specified")
        else:
            self.pmodel = ParametersModel(
                dataframe=read_csv(csvfile_parameters),
                theme=self.theme,
                drop_constants=drop_constants,
            )
            if self.csvfile_smry is not None:
                self.vmodel = SimulationTimeSeriesModel(
                    dataframe=read_csv(csvfile_smry))
            else:
                self.vmodel = None

        self._parameter_filter = ParameterFilter(app,
                                                 self.uuid("parameter-filter"),
                                                 self.pmodel.dataframe)

        self.set_callbacks(app)
Exemplo n.º 2
0
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        ensembles: list,
        wells: Optional[List[str]] = None,
    ):
        super().__init__()
        if wells is None:
            self.column_keys = ["WBHP:*"]
        else:
            self.column_keys = [f"WBHP:{well}" for well in wells]

        self.emodel: EnsembleSetModel = (
            caching_ensemble_set_model_factory.get_or_create_model(
                ensemble_paths={
                    ens:
                    webviz_settings.shared_settings["scratch_ensembles"][ens]
                    for ens in ensembles
                },
                time_index="raw",
                column_keys=self.column_keys,
            ))
        self.smry = self.emodel.get_or_load_smry_cached()
        self.theme = webviz_settings.theme
        self.set_callbacks(app)
Exemplo n.º 3
0
    def __init__(
        self,
        app: dash.Dash,
        webviz_settings: WebvizSettings,
        ensembles: Optional[list] = None,
        statistics_file: str = "share/results/tables/gridpropstatistics.csv",
        csvfile_statistics: pathlib.Path = None,
        csvfile_smry: pathlib.Path = None,
        surface_renaming: Optional[dict] = None,
        time_index: str = "monthly",
        column_keys: Optional[list] = None,
    ):
        super().__init__()
        WEBVIZ_ASSETS.add(
            pathlib.Path(webviz_subsurface.__file__).parent / "_assets" /
            "css" / "container.css")
        self.theme: WebvizConfigTheme = webviz_settings.theme
        self.time_index = time_index
        self.column_keys = column_keys
        self.statistics_file = statistics_file
        self.ensembles = ensembles
        self.csvfile_statistics = csvfile_statistics
        self.csvfile_smry = csvfile_smry
        self.surface_folders: Union[dict, None]

        if ensembles is not None:
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths={
                        ens:
                        webviz_settings.shared_settings["scratch_ensembles"]
                        [ens]
                        for ens in ensembles
                    },
                    time_index=self.time_index,
                    column_keys=self.column_keys,
                ))
            self.pmodel = PropertyStatisticsModel(
                dataframe=self.emodel.load_csv(
                    csv_file=pathlib.Path(self.statistics_file)),
                theme=self.theme,
            )
            self.vmodel = SimulationTimeSeriesModel(
                dataframe=self.emodel.get_or_load_smry_cached(),
                theme=self.theme,
            )
            self.surface_folders = {
                ens: folder / "share" / "results" / "maps" / ens
                for ens, folder in self.emodel.ens_folders.items()
            }
        else:
            self.pmodel = PropertyStatisticsModel(
                dataframe=read_csv(csvfile_statistics), theme=self.theme)
            self.vmodel = SimulationTimeSeriesModel(
                dataframe=read_csv(csvfile_smry), theme=self.theme)
            self.surface_folders = None

        self.surface_renaming = surface_renaming if surface_renaming else {}

        self.set_callbacks(app)
    def __init__(
        self,
        app: dash.Dash,
        webviz_settings: WebvizSettings,
        csvfile_vol: Path = None,
        csvfile_parameters: Path = None,
        ensembles: list = None,
        volfiles: dict = None,
        volfolder: str = "share/results/volumes",
        non_net_facies: Optional[List[str]] = None,
    ):

        super().__init__()

        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "container.css")
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "inplace_volumes.css")

        self.csvfile_vol = csvfile_vol
        self.csvfile_parameters = csvfile_parameters
        self.volfiles = volfiles
        self.volfolder = volfolder

        if csvfile_vol and ensembles:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile" or "ensembles" and "volfiles"'
            )
        if csvfile_vol:
            volumes_table = read_csv(csvfile_vol)
            parameters: Optional[pd.DataFrame] = (
                read_csv(csvfile_parameters) if csvfile_parameters else None)

        elif ensembles and volfiles:
            ensemble_paths = {
                ens: webviz_settings.shared_settings["scratch_ensembles"][ens]
                for ens in ensembles
            }
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths=ensemble_paths, ))
            parameters = self.emodel.load_parameters()
            volumes_table = extract_volumes(self.emodel, volfolder, volfiles)

        else:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile" or "ensembles" and "volfiles"'
            )

        self.volmodel = InplaceVolumesModel(
            volumes_table=volumes_table,
            parameter_table=parameters,
            non_net_facies=non_net_facies,
        )
        self.theme = webviz_settings.theme
        self.set_callbacks(app)
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        csvfile_smry: Path = None,
        csvfile_parameters: Path = None,
        ensembles: list = None,
        column_keys: list = None,
        initial_vector: str = None,
        sampling: str = "monthly",
        line_shape_fallback: str = "linear",
    ) -> None:

        super().__init__()

        self.time_index = sampling
        self.column_keys = column_keys
        self.csvfile_smry = csvfile_smry
        self.csvfile_parameters = csvfile_parameters

        if csvfile_smry and ensembles:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile_smry" and "csvfile_parameters" or '
                '"ensembles"')
        if csvfile_smry and csvfile_parameters:
            self.smry = read_csv(csvfile_smry)
            self.parameters = read_csv(csvfile_parameters)
            self.parameters["SENSTYPE"] = self.parameters.apply(
                lambda row: find_sens_type(row.SENSCASE), axis=1)
            self.smry_meta = None

        elif ensembles:
            self.ens_paths = {
                ensemble:
                webviz_settings.shared_settings["scratch_ensembles"][ensemble]
                for ensemble in ensembles
            }
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths=self.ens_paths,
                    time_index=self.time_index,
                    column_keys=self.column_keys,
                ))
            self.smry = self.emodel.get_or_load_smry_cached()
            self.smry_meta = self.emodel.load_smry_meta()

            # Extract realizations and sensitivity information
            self.parameters = get_realizations(ensemble_paths=self.ens_paths,
                                               ensemble_set_name="EnsembleSet")
        else:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile_smry" and "csvfile_parameters" or '
                '"ensembles"')
        self.smry_cols = [
            c for c in self.smry.columns
            if c not in ReservoirSimulationTimeSeriesOneByOne.ENSEMBLE_COLUMNS
            and historical_vector(c, self.smry_meta,
                                  False) not in self.smry.columns
        ]
        self.initial_vector = (initial_vector if initial_vector
                               and initial_vector in self.smry_cols else
                               self.smry_cols[0])
        self.ensembles = list(self.parameters["ENSEMBLE"].unique())
        self.line_shape_fallback = set_simulation_line_shape_fallback(
            line_shape_fallback)
        self.tornadoplot = TornadoWidget(app,
                                         webviz_settings,
                                         self.parameters,
                                         allow_click=True)
        self.uid = uuid4()
        self.theme = webviz_settings.theme
        self.set_callbacks(app)
Exemplo n.º 6
0
    def __init__(
        self,
        app,
        webviz_settings: WebvizSettings,
        parameter_csv: Path = None,
        response_csv: Path = None,
        ensembles: list = None,
        response_file: str = None,
        response_filters: dict = None,
        response_ignore: list = None,
        response_include: list = None,
        column_keys: list = None,
        sampling: str = "monthly",
        aggregation: str = "sum",
        corr_method: str = "pearson",
    ):

        super().__init__()

        self.parameter_csv = parameter_csv if parameter_csv else None
        self.response_csv = response_csv if response_csv else None
        self.response_file = response_file if response_file else None
        self.response_filters = response_filters if response_filters else {}
        self.column_keys = column_keys
        self.time_index = sampling
        self.corr_method = corr_method
        self.aggregation = aggregation
        if response_ignore and response_include:
            raise ValueError(
                'Incorrent argument. either provide "response_include", '
                '"response_ignore" or neither')
        if parameter_csv and response_csv:
            if ensembles or response_file:
                raise ValueError(
                    'Incorrect arguments. Either provide "csv files" or '
                    '"ensembles and response_file".')
            self.parameterdf = read_csv(self.parameter_csv)
            self.responsedf = read_csv(self.response_csv)

        elif ensembles:
            self.ens_paths = {
                ens: webviz_settings.shared_settings["scratch_ensembles"][ens]
                for ens in ensembles
            }
            self.parameterdf = load_parameters(ensemble_paths=self.ens_paths,
                                               ensemble_set_name="EnsembleSet")
            if self.response_file:
                self.responsedf = load_csv(
                    ensemble_paths=self.ens_paths,
                    csv_file=response_file,
                    ensemble_set_name="EnsembleSet",
                )
            else:
                self.emodel: EnsembleSetModel = (
                    caching_ensemble_set_model_factory.get_or_create_model(
                        ensemble_paths=self.ens_paths,
                        column_keys=self.column_keys,
                        time_index=self.time_index,
                    ))
                self.responsedf = self.emodel.get_or_load_smry_cached()
                self.response_filters["DATE"] = "single"
        else:
            raise ValueError(
                'Incorrect arguments. Either provide "csv files" or "ensembles and response_file".'
            )
        parresp.check_runs(self.parameterdf, self.responsedf)
        parresp.check_response_filters(self.responsedf, self.response_filters)

        # Only select numerical responses
        self.response_columns = parresp.filter_numerical_columns(
            df=self.responsedf,
            column_ignore=response_ignore,
            column_include=response_include,
            filter_columns=self.response_filters.keys(),
        )

        # Only select numerical parameters
        self.parameter_columns = parresp.filter_numerical_columns(
            df=self.parameterdf)

        self.theme = webviz_settings.theme
        self.set_callbacks(app)
Exemplo n.º 7
0
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        ensembles: Optional[list] = None,
        rel_file_pattern: str = "share/results/unsmry/*.arrow",
        statistics_file: str = "share/results/tables/gridpropstatistics.csv",
        surface_renaming: Optional[dict] = None,
        time_index: str = "monthly",
        column_keys: Optional[list] = None,
        csvfile_statistics: Path = None,
        csvfile_smry: Path = None,
    ):
        super().__init__()
        self.theme: WebvizConfigTheme = webviz_settings.theme
        self.ensembles = ensembles
        self._surface_folders: Union[dict, None] = None
        self._vmodel: Optional[Union[SimulationTimeSeriesModel,
                                     ProviderTimeSeriesDataModel]] = None
        run_mode_portable = WEBVIZ_INSTANCE_INFO.run_mode == WebvizRunMode.PORTABLE
        table_provider = EnsembleTableProviderFactory.instance()

        if ensembles is not None:
            ensemble_paths = {
                ensemble_name:
                webviz_settings.shared_settings["scratch_ensembles"]
                [ensemble_name]
                for ensemble_name in ensembles
            }

            resampling_frequency = Frequency(time_index)
            provider_factory = EnsembleSummaryProviderFactory.instance()

            try:
                provider_set = {
                    ens: provider_factory.create_from_arrow_unsmry_presampled(
                        str(ens_path), rel_file_pattern, resampling_frequency)
                    for ens, ens_path in ensemble_paths.items()
                }
                self._vmodel = ProviderTimeSeriesDataModel(
                    provider_set=provider_set, column_keys=column_keys)
                property_df = create_df_from_table_provider(
                    table_provider.
                    create_provider_set_from_per_realization_csv_file(
                        ensemble_paths, statistics_file))
            except ValueError as error:
                message = (
                    f"Some/all ensembles are missing arrow files at {rel_file_pattern}.\n"
                    "If no arrow files have been generated with `ERT` using `ECL2CSV`, "
                    "the commandline tool `smry2arrow_batch` can be used to generate arrow "
                    "files for an ensemble")
                if not run_mode_portable:
                    raise ValueError(message) from error

                # NOTE: this part below is to ensure backwards compatibility for portable app's
                # created before the arrow support. It should be removed in the future.
                emodel: EnsembleSetModel = (
                    caching_ensemble_set_model_factory.get_or_create_model(
                        ensemble_paths=ensemble_paths,
                        time_index=time_index,
                        column_keys=column_keys,
                    ))
                self._vmodel = SimulationTimeSeriesModel(
                    dataframe=emodel.get_or_load_smry_cached())
                property_df = emodel.load_csv(csv_file=Path(statistics_file))

            self._surface_folders = {
                ens: Path(ens_path.split("realization")[0]) /
                "share/results/maps" / ens
                for ens, ens_path in ensemble_paths.items()
            }

        else:
            if csvfile_statistics is None:
                raise ValueError(
                    "If not 'ensembles', then csvfile_statistics must be provided"
                )
            # NOTE: the try/except is for backwards compatibility with existing portable app's.
            # It should be removed in the future together with the support of aggregated csv-files
            try:
                property_df = create_df_from_table_provider(
                    table_provider.
                    create_provider_set_from_aggregated_csv_file(
                        csvfile_statistics))
            except FileNotFoundError:
                if not run_mode_portable:
                    raise
                property_df = read_csv(csvfile_statistics)

            if csvfile_smry is not None:
                try:
                    smry_df = create_df_from_table_provider(
                        table_provider.
                        create_provider_set_from_aggregated_csv_file(
                            csvfile_smry))
                except FileNotFoundError:
                    if not run_mode_portable:
                        raise
                    smry_df = read_csv(csvfile_smry)

                self._vmodel = SimulationTimeSeriesModel(dataframe=smry_df)

        self._pmodel = PropertyStatisticsModel(dataframe=property_df,
                                               theme=self.theme)

        self._surface_renaming = surface_renaming if surface_renaming else {}
        self._surface_table = generate_surface_table(
            statistics_dframe=self._pmodel.dataframe,
            ensembles=self._pmodel.ensembles,
            surface_folders=self._surface_folders,
            surface_renaming=self._surface_renaming,
        )
        self.set_callbacks(app)
    def __init__(
        self,
        app,
        webviz_settings: WebvizSettings,
        ensembles: list = None,
        parameter_csv: Path = None,
        response_csv: Path = None,
        response_file: str = None,
        response_filters: dict = None,
        response_ignore: list = None,
        response_include: list = None,
        parameter_ignore: list = None,
        column_keys: list = None,
        sampling: str = "monthly",
        aggregation: str = "sum",
        no_responses=False,
    ):

        super().__init__()

        self.parameter_csv = parameter_csv if parameter_csv else None
        self.response_csv = response_csv if response_csv else None
        self.response_file = response_file if response_file else None
        self.response_filters = response_filters if response_filters else {}
        self.column_keys = column_keys
        self.time_index = sampling
        self.aggregation = aggregation
        self.no_responses = no_responses
        self.response_columns = []

        if response_ignore and response_include:
            raise ValueError(
                'Incorrent argument. Either provide "response_include", '
                '"response_ignore" or neither')
        if parameter_csv:
            if ensembles or response_file:
                raise ValueError(
                    'Incorrect arguments. Either provide "parameter_csv" or '
                    '"ensembles and/or response_file".')
            if not self.no_responses:
                if self.response_csv:
                    self.responsedf = read_csv(self.response_csv)
                else:
                    raise ValueError(
                        "Incorrect arguments. Missing response_csv.")
            self.parameterdf = read_csv(self.parameter_csv)

        elif ensembles:
            if self.response_csv:
                raise ValueError(
                    'Incorrect arguments. Either provide "response_csv" or '
                    '"ensembles and/or response_file".')
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths={
                        ens:
                        webviz_settings.shared_settings["scratch_ensembles"]
                        [ens]
                        for ens in ensembles
                    },
                    time_index=self.time_index,
                    column_keys=self.column_keys,
                ))
            self.parameterdf = self.emodel.load_parameters()
            if not self.no_responses:
                if self.response_file:
                    self.responsedf = self.emodel.load_csv(
                        csv_file=response_file)
                else:
                    self.responsedf = self.emodel.get_or_load_smry_cached()
                    self.response_filters["DATE"] = "single"
        else:
            raise ValueError(
                "Incorrect arguments."
                'You have to define at least "ensembles" or "parameter_csv".')

        if not self.no_responses:
            parresp.check_runs(parameterdf=self.parameterdf,
                               responsedf=self.responsedf)
            parresp.check_response_filters(
                responsedf=self.responsedf,
                response_filters=self.response_filters)
            # only select numerical responses
            self.response_columns = parresp.filter_numerical_columns(
                df=self.responsedf,
                column_ignore=response_ignore,
                column_include=response_include,
                filter_columns=self.response_filters.keys(),
            )

        # Only select numerical parameters
        self.parameter_columns = parresp.filter_numerical_columns(
            df=self.parameterdf, column_ignore=parameter_ignore)

        self.theme = webviz_settings.theme
        self.set_callbacks(app)
    def __init__(
        self,
        app: dash.Dash,
        webviz_settings: WebvizSettings,
        csvfile: Path = None,
        ensembles: list = None,
        obsfile: Path = None,
        column_keys: list = None,
        sampling: str = "monthly",
        options: dict = None,
        line_shape_fallback: str = "linear",
    ):

        super().__init__()

        self.csvfile = csvfile
        self.obsfile = obsfile
        self.time_index = sampling
        self.column_keys = column_keys
        if csvfile and ensembles:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile" or "ensembles"'
            )
        self.observations = {}
        if obsfile:
            self.observations = check_and_format_observations(
                get_path(self.obsfile))

        self.smry: pd.DataFrame
        self.smry_meta: Union[pd.DataFrame, None]
        if csvfile:
            self.smry = read_csv(csvfile)
            self.smry_meta = None
            # Check of time_index for data to use in resampling. Quite naive as it only checks for
            # unique values of the DATE column, and not per realization.
            #
            # Currently not necessary as we don't allow resampling for average rates and intervals
            # unless we have metadata, which csvfile input currently doesn't support.
            # See: https://github.com/equinor/webviz-subsurface/issues/402
            self.time_index = pd.infer_freq(
                sorted(pd.to_datetime(self.smry["DATE"]).unique()))
        elif ensembles:
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths={
                        ens:
                        webviz_settings.shared_settings["scratch_ensembles"]
                        [ens]
                        for ens in ensembles
                    },
                    time_index=self.time_index,
                    column_keys=self.column_keys,
                ))
            self.smry = self.emodel.get_or_load_smry_cached()
            self.smry_meta = self.emodel.load_smry_meta()
        else:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile" or "ensembles"'
            )
        if any(
                col.startswith(("AVG_", "INTVL_"))
                for col in self.smry.columns):
            raise ValueError(
                "Your data set includes time series vectors which have names starting with"
                "'AVG_' and/or 'INTVL_'. These prefixes are not allowed, as they are used"
                "internally in the plugin.")
        self.smry_cols = [
            c for c in self.smry.columns
            if c not in ReservoirSimulationTimeSeries.ENSEMBLE_COLUMNS
            and not historical_vector(c, self.smry_meta,
                                      False) in self.smry.columns
        ]

        self.dropdown_options = []
        for vec in self.smry_cols:
            self.dropdown_options.append({
                "label": f"{simulation_vector_description(vec)} ({vec})",
                "value": vec
            })
            if (self.smry_meta is not None and self.smry_meta.is_total[vec]
                    and self.time_index is not None):
                # Get the likely name for equivalent rate vector and make dropdown options.
                # Requires that the time_index was either defined or possible to infer.
                avgrate_vec = rename_vec_from_cum(vector=vec, as_rate=True)
                interval_vec = rename_vec_from_cum(vector=vec, as_rate=False)
                self.dropdown_options.append({
                    "label":
                    f"{simulation_vector_description(avgrate_vec)} ({avgrate_vec})",
                    "value": avgrate_vec,
                })
                self.dropdown_options.append({
                    "label":
                    f"{simulation_vector_description(interval_vec)} ({interval_vec})",
                    "value": interval_vec,
                })

        self.ensembles = list(self.smry["ENSEMBLE"].unique())
        self.theme = webviz_settings.theme
        self.plot_options = options if options else {}
        self.plot_options["date"] = (str(self.plot_options.get("date")) if
                                     self.plot_options.get("date") else None)
        self.line_shape_fallback = set_simulation_line_shape_fallback(
            line_shape_fallback)
        # Check if initially plotted vectors exist in data, raise ValueError if not.
        missing_vectors = [
            value for key, value in self.plot_options.items()
            if key in ["vector1", "vector2", "vector3"]
            and value not in self.smry_cols
        ]
        if missing_vectors:
            raise ValueError(
                f"Cannot find: {', '.join(missing_vectors)} to plot initially in "
                "ReservoirSimulationTimeSeries. Check that the vectors exist in your data, and "
                "that they are not missing in a non-default column_keys list in the yaml config "
                "file.")
        self.allow_delta = len(self.ensembles) > 1
        self.set_callbacks(app)
Exemplo n.º 10
0
    def __init__(
        self,
        webviz_settings: WebvizSettings,
        ensembles: Optional[List[str]],
        formations: Path = None,
        faultlines: Path = None,
        obsdata: Path = None,
        csvfile_rft: Path = None,
        csvfile_rft_ert: Path = None,
    ):
        self.formations = formations
        self.faultlines = faultlines
        self.obsdata = obsdata
        self.csvfile_rft = csvfile_rft
        self.csvfile_rft_ert = csvfile_rft_ert

        if csvfile_rft_ert and ensembles:
            raise ValueError(
                'Incorrent arguments. Either provide a "csvfile_rft_ert" or "ensembles"'
            )

        self.simdf = read_csv(
            self.csvfile_rft) if csvfile_rft is not None else None
        self.formationdf = read_csv(
            self.formations) if self.formations else None
        self.faultlinesdf = read_csv(
            self.faultlines) if self.faultlines else None
        self.obsdatadf = read_csv(self.obsdata) if self.obsdata else None
        self.ertdatadf = pd.DataFrame()

        if csvfile_rft_ert is not None:
            self.ertdatadf = read_csv(self.csvfile_rft_ert)
            self.param_model = ParametersModel(pd.DataFrame())

        if ensembles is not None:
            ens_paths = {
                ens: webviz_settings.shared_settings["scratch_ensembles"][ens]
                for ens in ensembles
            }
            self.emodel: EnsembleSetModel = (
                caching_ensemble_set_model_factory.get_or_create_model(
                    ensemble_paths=ens_paths, ))
            try:
                self.simdf = self.emodel.load_csv(
                    Path("share/results/tables/rft.csv"))
            except (KeyError, OSError):
                self.simdf = None

            self.param_model = ParametersModel(
                dataframe=self.emodel.load_parameters(),
                drop_constants=True,
                keep_numeric_only=True,
            )

            try:
                self.ertdatadf = self.emodel.load_csv(
                    Path("share/results/tables/rft_ert.csv"))
            except KeyError as exc:
                raise KeyError(
                    "CSV file for ERT RFT observations/simulations "
                    "(share/results/tables/rft_ert.csv) not found!") from exc

        self.ertdatadf = self.ertdatadf.rename(
            columns={
                "time": "DATE",
                "is_active": "ACTIVE",
                "isactive": "ACTIVE",
                "well": "WELL",
                "zone": "ZONE",
                "pressure": "SIMULATED",
                "true_vertical_depth": "TVD",
                "measured_depth": "MD",
                "observed": "OBSERVED",
                "obs": "OBSERVED",
                "error": "OBSERVED_ERR",
                "utm_x": "EAST",
                "utm_y": "NORTH",
            })
        self.ertdatadf["DIFF"] = (self.ertdatadf["SIMULATED"] -
                                  self.ertdatadf["OBSERVED"])
        self.ertdatadf["ABSDIFF"] = abs(self.ertdatadf["SIMULATED"] -
                                        self.ertdatadf["OBSERVED"])
        self.ertdatadf["YEAR"] = pd.to_datetime(self.ertdatadf["DATE"]).dt.year
        self.ertdatadf = self.ertdatadf.sort_values(by="DATE")
        self.ertdatadf["DATE_IDX"] = self.ertdatadf["DATE"].apply(
            lambda x: list(self.ertdatadf["DATE"].unique()).index(x))
        self.date_marks = self.set_date_marks()
        self.ertdatadf = filter_frame(
            self.ertdatadf,
            {
                "ACTIVE": 1,
            },
        )
        self.ertdatadf["STDDEV"] = self.ertdatadf.groupby(
            ["WELL", "DATE", "ZONE", "ENSEMBLE",
             "TVD"])["SIMULATED"].transform("std")