ert 17.0.0__py3-none-any.whl → 19.0.0rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _ert/events.py +19 -2
- _ert/forward_model_runner/client.py +6 -2
- ert/__main__.py +28 -13
- ert/analysis/_enif_update.py +8 -4
- ert/analysis/_es_update.py +19 -6
- ert/analysis/_update_commons.py +16 -6
- ert/cli/main.py +13 -6
- ert/cli/monitor.py +7 -0
- ert/config/__init__.py +15 -6
- ert/config/_create_observation_dataframes.py +117 -20
- ert/config/_get_num_cpu.py +1 -1
- ert/config/_observations.py +91 -2
- ert/config/_read_summary.py +8 -6
- ert/config/design_matrix.py +51 -24
- ert/config/distribution.py +1 -1
- ert/config/ensemble_config.py +9 -17
- ert/config/ert_config.py +103 -19
- ert/config/everest_control.py +234 -0
- ert/config/{everest_objective_config.py → everest_response.py} +24 -15
- ert/config/field.py +96 -84
- ert/config/forward_model_step.py +122 -17
- ert/config/gen_data_config.py +5 -10
- ert/config/gen_kw_config.py +5 -35
- ert/config/known_response_types.py +14 -0
- ert/config/parameter_config.py +1 -33
- ert/config/parsing/_option_dict.py +10 -2
- ert/config/parsing/config_keywords.py +2 -0
- ert/config/parsing/config_schema.py +23 -3
- ert/config/parsing/config_schema_deprecations.py +3 -14
- ert/config/parsing/config_schema_item.py +26 -11
- ert/config/parsing/context_values.py +3 -3
- ert/config/parsing/file_context_token.py +1 -1
- ert/config/parsing/observations_parser.py +6 -2
- ert/config/parsing/queue_system.py +9 -0
- ert/config/parsing/schema_item_type.py +1 -0
- ert/config/queue_config.py +4 -5
- ert/config/response_config.py +0 -8
- ert/config/rft_config.py +275 -0
- ert/config/summary_config.py +3 -8
- ert/config/surface_config.py +59 -16
- ert/config/workflow_fixtures.py +2 -1
- ert/dark_storage/client/__init__.py +2 -2
- ert/dark_storage/client/_session.py +4 -4
- ert/dark_storage/client/client.py +2 -2
- ert/dark_storage/common.py +1 -1
- ert/dark_storage/compute/misfits.py +11 -7
- ert/dark_storage/endpoints/compute/misfits.py +6 -4
- ert/dark_storage/endpoints/experiment_server.py +12 -9
- ert/dark_storage/endpoints/experiments.py +2 -2
- ert/dark_storage/endpoints/observations.py +8 -6
- ert/dark_storage/endpoints/parameters.py +2 -18
- ert/dark_storage/endpoints/responses.py +24 -5
- ert/dark_storage/json_schema/experiment.py +1 -1
- ert/data/_measured_data.py +6 -5
- ert/ensemble_evaluator/__init__.py +8 -1
- ert/ensemble_evaluator/config.py +2 -1
- ert/ensemble_evaluator/evaluator.py +81 -29
- ert/ensemble_evaluator/event.py +6 -0
- ert/ensemble_evaluator/snapshot.py +3 -1
- ert/ensemble_evaluator/state.py +1 -0
- ert/field_utils/__init__.py +8 -0
- ert/field_utils/field_utils.py +212 -3
- ert/field_utils/roff_io.py +1 -1
- ert/gui/__init__.py +5 -2
- ert/gui/ertnotifier.py +1 -1
- ert/gui/ertwidgets/__init__.py +23 -16
- ert/gui/ertwidgets/analysismoduleedit.py +2 -2
- ert/gui/ertwidgets/checklist.py +1 -1
- ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
- ert/gui/ertwidgets/ensembleselector.py +2 -2
- ert/gui/ertwidgets/models/__init__.py +2 -0
- ert/gui/ertwidgets/models/activerealizationsmodel.py +2 -1
- ert/gui/ertwidgets/models/path_model.py +1 -1
- ert/gui/ertwidgets/models/targetensemblemodel.py +2 -1
- ert/gui/ertwidgets/models/text_model.py +1 -1
- ert/gui/ertwidgets/pathchooser.py +0 -3
- ert/gui/ertwidgets/searchbox.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +63 -30
- ert/gui/main.py +37 -8
- ert/gui/main_window.py +1 -7
- ert/gui/simulation/ensemble_experiment_panel.py +1 -1
- ert/gui/simulation/ensemble_information_filter_panel.py +1 -1
- ert/gui/simulation/ensemble_smoother_panel.py +1 -1
- ert/gui/simulation/evaluate_ensemble_panel.py +1 -1
- ert/gui/simulation/experiment_panel.py +16 -3
- ert/gui/simulation/manual_update_panel.py +31 -8
- ert/gui/simulation/multiple_data_assimilation_panel.py +12 -8
- ert/gui/simulation/run_dialog.py +27 -20
- ert/gui/simulation/single_test_run_panel.py +2 -2
- ert/gui/summarypanel.py +20 -1
- ert/gui/tools/load_results/load_results_panel.py +1 -1
- ert/gui/tools/manage_experiments/export_dialog.py +136 -0
- ert/gui/tools/manage_experiments/storage_info_widget.py +121 -16
- ert/gui/tools/manage_experiments/storage_widget.py +1 -2
- ert/gui/tools/plot/plot_api.py +37 -25
- ert/gui/tools/plot/plot_widget.py +10 -2
- ert/gui/tools/plot/plot_window.py +38 -18
- ert/gui/tools/plot/plottery/plot_config.py +2 -0
- ert/gui/tools/plot/plottery/plot_context.py +14 -0
- ert/gui/tools/plot/plottery/plots/__init__.py +2 -0
- ert/gui/tools/plot/plottery/plots/cesp.py +3 -1
- ert/gui/tools/plot/plottery/plots/distribution.py +6 -1
- ert/gui/tools/plot/plottery/plots/ensemble.py +12 -3
- ert/gui/tools/plot/plottery/plots/gaussian_kde.py +12 -2
- ert/gui/tools/plot/plottery/plots/histogram.py +3 -1
- ert/gui/tools/plot/plottery/plots/misfits.py +436 -0
- ert/gui/tools/plot/plottery/plots/observations.py +18 -4
- ert/gui/tools/plot/plottery/plots/statistics.py +62 -20
- ert/gui/tools/plot/plottery/plots/std_dev.py +3 -1
- ert/mode_definitions.py +2 -0
- ert/plugins/__init__.py +0 -1
- ert/plugins/hook_implementations/workflows/csv_export.py +2 -3
- ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
- ert/plugins/hook_specifications/__init__.py +0 -2
- ert/plugins/hook_specifications/jobs.py +0 -9
- ert/plugins/plugin_manager.py +6 -33
- ert/resources/forward_models/run_reservoirsimulator.py +8 -3
- ert/resources/shell_scripts/delete_directory.py +2 -2
- ert/run_models/__init__.py +18 -5
- ert/run_models/_create_run_path.py +131 -37
- ert/run_models/ensemble_experiment.py +10 -4
- ert/run_models/ensemble_information_filter.py +8 -1
- ert/run_models/ensemble_smoother.py +9 -3
- ert/run_models/evaluate_ensemble.py +8 -6
- ert/run_models/event.py +7 -3
- ert/run_models/everest_run_model.py +159 -46
- ert/run_models/initial_ensemble_run_model.py +25 -24
- ert/run_models/manual_update.py +6 -3
- ert/run_models/manual_update_enif.py +37 -0
- ert/run_models/model_factory.py +81 -21
- ert/run_models/multiple_data_assimilation.py +22 -11
- ert/run_models/run_model.py +64 -55
- ert/run_models/single_test_run.py +7 -4
- ert/run_models/update_run_model.py +4 -2
- ert/runpaths.py +5 -6
- ert/sample_prior.py +9 -4
- ert/scheduler/driver.py +37 -0
- ert/scheduler/event.py +3 -1
- ert/scheduler/job.py +23 -13
- ert/scheduler/lsf_driver.py +6 -2
- ert/scheduler/openpbs_driver.py +7 -1
- ert/scheduler/scheduler.py +5 -0
- ert/scheduler/slurm_driver.py +6 -2
- ert/services/__init__.py +2 -2
- ert/services/_base_service.py +37 -20
- ert/services/ert_server.py +317 -0
- ert/shared/_doc_utils/__init__.py +4 -2
- ert/shared/_doc_utils/ert_jobs.py +1 -4
- ert/shared/net_utils.py +43 -18
- ert/shared/storage/connection.py +3 -3
- ert/shared/version.py +3 -3
- ert/storage/__init__.py +2 -0
- ert/storage/local_ensemble.py +38 -12
- ert/storage/local_experiment.py +8 -16
- ert/storage/local_storage.py +68 -42
- ert/storage/migration/to11.py +1 -1
- ert/storage/migration/to16.py +38 -0
- ert/storage/migration/to17.py +42 -0
- ert/storage/migration/to18.py +11 -0
- ert/storage/migration/to19.py +34 -0
- ert/storage/migration/to20.py +23 -0
- ert/storage/migration/to21.py +25 -0
- ert/storage/migration/to8.py +4 -4
- ert/substitutions.py +12 -28
- ert/validation/active_range.py +7 -7
- ert/validation/rangestring.py +16 -16
- ert/workflow_runner.py +2 -1
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/METADATA +9 -8
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/RECORD +208 -205
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/WHEEL +1 -1
- everest/api/everest_data_api.py +14 -1
- everest/bin/config_branch_script.py +3 -6
- everest/bin/everconfigdump_script.py +1 -9
- everest/bin/everest_script.py +21 -11
- everest/bin/everlint_script.py +0 -2
- everest/bin/kill_script.py +2 -2
- everest/bin/monitor_script.py +2 -2
- everest/bin/utils.py +8 -4
- everest/bin/visualization_script.py +6 -14
- everest/config/__init__.py +4 -1
- everest/config/control_config.py +81 -6
- everest/config/control_variable_config.py +4 -3
- everest/config/everest_config.py +75 -42
- everest/config/forward_model_config.py +5 -3
- everest/config/install_data_config.py +7 -5
- everest/config/install_job_config.py +7 -3
- everest/config/install_template_config.py +3 -3
- everest/config/optimization_config.py +19 -6
- everest/config/output_constraint_config.py +8 -2
- everest/config/server_config.py +6 -49
- everest/config/utils.py +25 -105
- everest/config/validation_utils.py +17 -11
- everest/config_file_loader.py +13 -4
- everest/detached/client.py +3 -3
- everest/detached/everserver.py +7 -8
- everest/everest_storage.py +6 -12
- everest/gui/everest_client.py +2 -3
- everest/gui/main_window.py +2 -2
- everest/optimizer/everest2ropt.py +59 -32
- everest/optimizer/opt_model_transforms.py +12 -13
- everest/optimizer/utils.py +0 -29
- everest/strings.py +0 -5
- ert/config/everest_constraints_config.py +0 -95
- ert/config/ext_param_config.py +0 -106
- ert/gui/tools/export/__init__.py +0 -3
- ert/gui/tools/export/export_panel.py +0 -83
- ert/gui/tools/export/export_tool.py +0 -69
- ert/gui/tools/export/exporter.py +0 -36
- ert/services/storage_service.py +0 -127
- everest/config/sampler_config.py +0 -103
- everest/simulator/__init__.py +0 -88
- everest/simulator/everest_to_ert.py +0 -51
- /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
- /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/entry_points.txt +0 -0
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/licenses/COPYING +0 -0
- {ert-17.0.0.dist-info → ert-19.0.0rc2.dist-info}/top_level.txt +0 -0
ert/config/surface_config.py
CHANGED
|
@@ -10,11 +10,16 @@ import xarray as xr
|
|
|
10
10
|
from pydantic import field_serializer
|
|
11
11
|
from surfio import IrapHeader, IrapSurface
|
|
12
12
|
|
|
13
|
+
from ert.field_utils import (
|
|
14
|
+
calc_rho_for_2d_grid_layer,
|
|
15
|
+
transform_local_ellipse_angle_to_local_coords,
|
|
16
|
+
transform_positions_to_local_field_coordinates,
|
|
17
|
+
)
|
|
13
18
|
from ert.substitutions import substitute_runpath_name
|
|
14
19
|
|
|
15
20
|
from ._str_to_bool import str_to_bool
|
|
16
21
|
from .field import create_flattened_cube_graph
|
|
17
|
-
from .parameter_config import InvalidParameterFile, ParameterConfig
|
|
22
|
+
from .parameter_config import InvalidParameterFile, ParameterConfig
|
|
18
23
|
from .parsing import ConfigValidationError, ErrorInfo
|
|
19
24
|
|
|
20
25
|
if TYPE_CHECKING:
|
|
@@ -46,6 +51,7 @@ class SurfaceMismatchError(InvalidParameterFile):
|
|
|
46
51
|
|
|
47
52
|
class SurfaceConfig(ParameterConfig):
|
|
48
53
|
type: Literal["surface"] = "surface"
|
|
54
|
+
dimensionality: Literal[2] = 2
|
|
49
55
|
ncol: int
|
|
50
56
|
nrow: int
|
|
51
57
|
xori: float
|
|
@@ -70,21 +76,6 @@ class SurfaceConfig(ParameterConfig):
|
|
|
70
76
|
def parameter_keys(self) -> list[str]:
|
|
71
77
|
return []
|
|
72
78
|
|
|
73
|
-
@property
|
|
74
|
-
def metadata(self) -> list[ParameterMetadata]:
|
|
75
|
-
return [
|
|
76
|
-
ParameterMetadata(
|
|
77
|
-
key=self.name,
|
|
78
|
-
dimensionality=2,
|
|
79
|
-
transformation=None,
|
|
80
|
-
userdata={
|
|
81
|
-
"data_origin": "SURFACE",
|
|
82
|
-
"nx": self.ncol,
|
|
83
|
-
"ny": self.nrow,
|
|
84
|
-
},
|
|
85
|
-
)
|
|
86
|
-
]
|
|
87
|
-
|
|
88
79
|
@classmethod
|
|
89
80
|
def from_config_list(cls, config_list: list[str | dict[str, str]]) -> Self:
|
|
90
81
|
name = cast(str, config_list[0])
|
|
@@ -248,3 +239,55 @@ class SurfaceConfig(ParameterConfig):
|
|
|
248
239
|
this flattening process"""
|
|
249
240
|
|
|
250
241
|
return create_flattened_cube_graph(px=self.ncol, py=self.nrow, pz=1)
|
|
242
|
+
|
|
243
|
+
def calc_rho_for_2d_grid_layer(
|
|
244
|
+
self,
|
|
245
|
+
obs_xpos: npt.NDArray[np.float64],
|
|
246
|
+
obs_ypos: npt.NDArray[np.float64],
|
|
247
|
+
obs_main_range: npt.NDArray[np.float64],
|
|
248
|
+
obs_perp_range: npt.NDArray[np.float64],
|
|
249
|
+
obs_anisotropy_angle: npt.NDArray[np.float64],
|
|
250
|
+
) -> npt.NDArray[np.float64]:
|
|
251
|
+
"""Function to calculate scaling values to be used in the RHO matrix
|
|
252
|
+
for distance-based localization.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
obs_xpos: x-coordinates in global coordinates of observations
|
|
256
|
+
obs_ypos: y-coordinates in global coordinates of observations
|
|
257
|
+
obs_main_range: Size of influence ellipse main principal direction.
|
|
258
|
+
obs_perp_range: Size of influence ellipse second principal direction.
|
|
259
|
+
obs_anisotropy_angle: Rotation angle anticlock wise of main principal
|
|
260
|
+
direction of influence ellipse relative to global coordinate
|
|
261
|
+
system's x-axis.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Scaling values (elements of the RHO matrix) as a numpy array
|
|
265
|
+
of shape=(nx,ny,nobservations)
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
# Transform observation positions to local surface coordinates
|
|
269
|
+
xpos, ypos = transform_positions_to_local_field_coordinates(
|
|
270
|
+
(self.xori, self.yori), self.rotation, obs_xpos, obs_ypos
|
|
271
|
+
)
|
|
272
|
+
# Transform ellipse orientation to local surface coordinates
|
|
273
|
+
rotation_angle_of_localization_ellipse = (
|
|
274
|
+
transform_local_ellipse_angle_to_local_coords(
|
|
275
|
+
self.rotation, obs_anisotropy_angle
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Assume the coordinate system is not flipped.
|
|
280
|
+
# This means the right_handed_grid_indexing is False
|
|
281
|
+
assert self.yflip == 1
|
|
282
|
+
return calc_rho_for_2d_grid_layer(
|
|
283
|
+
self.ncol,
|
|
284
|
+
self.nrow,
|
|
285
|
+
self.xinc,
|
|
286
|
+
self.yinc,
|
|
287
|
+
xpos,
|
|
288
|
+
ypos,
|
|
289
|
+
obs_main_range,
|
|
290
|
+
obs_perp_range,
|
|
291
|
+
rotation_angle_of_localization_ellipse,
|
|
292
|
+
right_handed_grid_indexing=False,
|
|
293
|
+
)
|
ert/config/workflow_fixtures.py
CHANGED
|
@@ -6,12 +6,13 @@ import typing
|
|
|
6
6
|
from dataclasses import dataclass, fields
|
|
7
7
|
from typing import TYPE_CHECKING, Literal
|
|
8
8
|
|
|
9
|
-
from PyQt6.QtWidgets import QWidget
|
|
10
9
|
from typing_extensions import TypedDict
|
|
11
10
|
|
|
12
11
|
from ert.config.parsing.hook_runtime import HookRuntime
|
|
13
12
|
|
|
14
13
|
if TYPE_CHECKING:
|
|
14
|
+
from PyQt6.QtWidgets import QWidget
|
|
15
|
+
|
|
15
16
|
from ert.config import ESSettings, ObservationSettings
|
|
16
17
|
from ert.runpaths import Runpaths
|
|
17
18
|
from ert.storage import Ensemble, Storage
|
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from pydantic import BaseModel, ValidationError
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class
|
|
8
|
+
class ErtClientConnectionInfo(BaseModel):
|
|
9
9
|
base_url: str
|
|
10
10
|
auth_token: str | None = None
|
|
11
11
|
cert: str | bool = False
|
|
@@ -17,10 +17,10 @@ ENV_VAR = "ERT_STORAGE_CONNECTION_STRING"
|
|
|
17
17
|
# that a single client process will only ever want to connect to a single ERT
|
|
18
18
|
# Storage server during its lifetime, so we don't provide an API for managing
|
|
19
19
|
# this cache.
|
|
20
|
-
_CACHED_CONN_INFO:
|
|
20
|
+
_CACHED_CONN_INFO: ErtClientConnectionInfo | None = None
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def find_conn_info() ->
|
|
23
|
+
def find_conn_info() -> ErtClientConnectionInfo:
|
|
24
24
|
"""
|
|
25
25
|
The base url and auth token are read from either:
|
|
26
26
|
The file `storage_server.json`, starting from the current working directory
|
|
@@ -54,7 +54,7 @@ def find_conn_info() -> ConnInfo:
|
|
|
54
54
|
raise RuntimeError("No Storage connection configuration found")
|
|
55
55
|
|
|
56
56
|
try:
|
|
57
|
-
conn_info =
|
|
57
|
+
conn_info = ErtClientConnectionInfo.model_validate_json(conn_str)
|
|
58
58
|
except (json.JSONDecodeError, ValidationError) as e:
|
|
59
59
|
raise RuntimeError("Invalid storage connection configuration") from e
|
|
60
60
|
else:
|
|
@@ -3,7 +3,7 @@ import ssl
|
|
|
3
3
|
import httpx
|
|
4
4
|
from httpx_retries import Retry, RetryTransport
|
|
5
5
|
|
|
6
|
-
from ._session import
|
|
6
|
+
from ._session import ErtClientConnectionInfo, find_conn_info
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Client(httpx.Client):
|
|
@@ -14,7 +14,7 @@ class Client(httpx.Client):
|
|
|
14
14
|
Stores 'conn_info' to bridge the gap to the Everest client setup
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
def __init__(self, conn_info:
|
|
17
|
+
def __init__(self, conn_info: ErtClientConnectionInfo | None = None) -> None:
|
|
18
18
|
if conn_info is None:
|
|
19
19
|
conn_info = find_conn_info()
|
|
20
20
|
|
ert/dark_storage/common.py
CHANGED
|
@@ -5,17 +5,18 @@ import numpy.typing as npt
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def _calculate_signed_chi_squared_misfit(
|
|
9
9
|
obs_value: npt.NDArray[np.float64],
|
|
10
10
|
response_value: npt.NDArray[np.float64],
|
|
11
11
|
obs_std: npt.NDArray[np.float64],
|
|
12
12
|
) -> list[float]:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"""The signed version is intended for visualization. For data assimiliation one
|
|
14
|
+
would normally use the normal chi-square"""
|
|
15
|
+
residual = response_value - obs_value
|
|
16
|
+
return (np.sign(residual) * residual * residual / (obs_std * obs_std)).tolist()
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
def
|
|
19
|
+
def calculate_signed_chi_squared_misfits(
|
|
19
20
|
reponses_dict: Mapping[int, pd.DataFrame],
|
|
20
21
|
observation: pd.DataFrame,
|
|
21
22
|
summary_misfits: bool = False,
|
|
@@ -26,9 +27,12 @@ def calculate_misfits_from_pandas(
|
|
|
26
27
|
"""
|
|
27
28
|
misfits_dict = {}
|
|
28
29
|
for realization_index in reponses_dict:
|
|
29
|
-
misfits_dict[realization_index] =
|
|
30
|
+
misfits_dict[realization_index] = _calculate_signed_chi_squared_misfit(
|
|
30
31
|
observation["values"],
|
|
31
|
-
reponses_dict[realization_index]
|
|
32
|
+
reponses_dict[realization_index]
|
|
33
|
+
.loc[:, observation.index]
|
|
34
|
+
.to_numpy()
|
|
35
|
+
.flatten(),
|
|
32
36
|
observation["errors"],
|
|
33
37
|
)
|
|
34
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Annotated, Any
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
|
|
6
6
|
import pandas as pd
|
|
@@ -10,7 +10,7 @@ from fastapi.responses import Response
|
|
|
10
10
|
|
|
11
11
|
from ert.dark_storage import exceptions as exc
|
|
12
12
|
from ert.dark_storage.common import get_storage
|
|
13
|
-
from ert.dark_storage.compute.misfits import
|
|
13
|
+
from ert.dark_storage.compute.misfits import calculate_signed_chi_squared_misfits
|
|
14
14
|
from ert.dark_storage.endpoints.observations import (
|
|
15
15
|
_get_observations,
|
|
16
16
|
)
|
|
@@ -36,7 +36,9 @@ async def get_response_misfits(
|
|
|
36
36
|
response_name: str,
|
|
37
37
|
realization_index: int | None = None,
|
|
38
38
|
summary_misfits: bool = False,
|
|
39
|
-
filter_on:
|
|
39
|
+
filter_on: Annotated[
|
|
40
|
+
str | None, Query(description="JSON string with filters")
|
|
41
|
+
] = None,
|
|
40
42
|
) -> Response:
|
|
41
43
|
ensemble = storage.get_ensemble(ensemble_id)
|
|
42
44
|
dataframe = data_for_response(
|
|
@@ -80,7 +82,7 @@ async def get_response_misfits(
|
|
|
80
82
|
index=[parse_index(x) for x in o["x_axis"]],
|
|
81
83
|
)
|
|
82
84
|
try:
|
|
83
|
-
result_df =
|
|
85
|
+
result_df = calculate_signed_chi_squared_misfits(
|
|
84
86
|
response_dict, observation_df, summary_misfits
|
|
85
87
|
)
|
|
86
88
|
except Exception as misfits_exc:
|
|
@@ -9,6 +9,7 @@ import traceback
|
|
|
9
9
|
import uuid
|
|
10
10
|
from base64 import b64decode
|
|
11
11
|
from queue import SimpleQueue
|
|
12
|
+
from typing import Annotated
|
|
12
13
|
|
|
13
14
|
from fastapi import (
|
|
14
15
|
APIRouter,
|
|
@@ -153,7 +154,7 @@ def _log(request: Request) -> None:
|
|
|
153
154
|
|
|
154
155
|
@router.get("/")
|
|
155
156
|
def get_status(
|
|
156
|
-
request: Request, credentials: HTTPBasicCredentials
|
|
157
|
+
request: Request, credentials: Annotated[HTTPBasicCredentials, Depends(security)]
|
|
157
158
|
) -> PlainTextResponse:
|
|
158
159
|
_log(request)
|
|
159
160
|
_check_user(credentials)
|
|
@@ -162,7 +163,7 @@ def get_status(
|
|
|
162
163
|
|
|
163
164
|
@router.get("/status")
|
|
164
165
|
def experiment_status(
|
|
165
|
-
request: Request, credentials: HTTPBasicCredentials
|
|
166
|
+
request: Request, credentials: Annotated[HTTPBasicCredentials, Depends(security)]
|
|
166
167
|
) -> ExperimentStatus:
|
|
167
168
|
_log(request)
|
|
168
169
|
_check_user(credentials)
|
|
@@ -171,7 +172,7 @@ def experiment_status(
|
|
|
171
172
|
|
|
172
173
|
@router.post("/" + EverEndpoints.stop)
|
|
173
174
|
def stop(
|
|
174
|
-
request: Request, credentials: HTTPBasicCredentials
|
|
175
|
+
request: Request, credentials: Annotated[HTTPBasicCredentials, Depends(security)]
|
|
175
176
|
) -> Response:
|
|
176
177
|
_log(request)
|
|
177
178
|
_check_user(credentials)
|
|
@@ -185,7 +186,7 @@ def stop(
|
|
|
185
186
|
async def start_experiment(
|
|
186
187
|
request: Request,
|
|
187
188
|
background_tasks: BackgroundTasks,
|
|
188
|
-
credentials: HTTPBasicCredentials
|
|
189
|
+
credentials: Annotated[HTTPBasicCredentials, Depends(security)],
|
|
189
190
|
) -> Response:
|
|
190
191
|
_log(request)
|
|
191
192
|
_check_user(credentials)
|
|
@@ -218,7 +219,7 @@ async def start_experiment(
|
|
|
218
219
|
|
|
219
220
|
@router.get("/" + EverEndpoints.config_path)
|
|
220
221
|
async def config_path(
|
|
221
|
-
request: Request, credentials: HTTPBasicCredentials
|
|
222
|
+
request: Request, credentials: Annotated[HTTPBasicCredentials, Depends(security)]
|
|
222
223
|
) -> JSONResponse:
|
|
223
224
|
_log(request)
|
|
224
225
|
_check_user(credentials)
|
|
@@ -237,7 +238,7 @@ async def config_path(
|
|
|
237
238
|
|
|
238
239
|
@router.get("/" + EverEndpoints.start_time)
|
|
239
240
|
async def start_time(
|
|
240
|
-
request: Request, credentials: HTTPBasicCredentials
|
|
241
|
+
request: Request, credentials: Annotated[HTTPBasicCredentials, Depends(security)]
|
|
241
242
|
) -> Response:
|
|
242
243
|
_log(request)
|
|
243
244
|
_check_user(credentials)
|
|
@@ -316,9 +317,11 @@ class ExperimentRunner:
|
|
|
316
317
|
simulation_future = loop.run_in_executor(
|
|
317
318
|
None,
|
|
318
319
|
lambda: run_model.start_simulations_thread(
|
|
319
|
-
EvaluatorServerConfig(
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
EvaluatorServerConfig(
|
|
321
|
+
use_ipc_protocol=run_model.queue_config.queue_system
|
|
322
|
+
== QueueSystem.LOCAL,
|
|
323
|
+
prioritize_private_ip_address=site_plugins.prioritize_private_ip_address,
|
|
324
|
+
)
|
|
322
325
|
),
|
|
323
326
|
)
|
|
324
327
|
while True:
|
|
@@ -29,7 +29,7 @@ def get_experiments(
|
|
|
29
29
|
priors=create_priors(experiment),
|
|
30
30
|
userdata={},
|
|
31
31
|
parameters={
|
|
32
|
-
group:
|
|
32
|
+
group: config.model_dump()
|
|
33
33
|
for group, config in experiment.parameter_configuration.items()
|
|
34
34
|
if not isinstance(config, SurfaceConfig)
|
|
35
35
|
},
|
|
@@ -65,7 +65,7 @@ def get_experiment_by_id(
|
|
|
65
65
|
priors=create_priors(experiment),
|
|
66
66
|
userdata={},
|
|
67
67
|
parameters={
|
|
68
|
-
group:
|
|
68
|
+
group: config.model_dump()
|
|
69
69
|
for group, config in experiment.parameter_configuration.items()
|
|
70
70
|
},
|
|
71
71
|
responses={
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import operator
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Annotated, Any
|
|
5
5
|
from urllib.parse import unquote
|
|
6
6
|
from uuid import UUID, uuid4
|
|
7
7
|
|
|
@@ -57,7 +57,9 @@ async def get_observations_for_response(
|
|
|
57
57
|
storage: Storage = DEFAULT_STORAGE,
|
|
58
58
|
ensemble_id: UUID,
|
|
59
59
|
response_key: str,
|
|
60
|
-
filter_on:
|
|
60
|
+
filter_on: Annotated[
|
|
61
|
+
str | None, Query(description="JSON string with filters")
|
|
62
|
+
] = None,
|
|
61
63
|
) -> list[js.ObservationOut]:
|
|
62
64
|
response_key = unquote(response_key)
|
|
63
65
|
try:
|
|
@@ -136,13 +138,13 @@ def _get_observations(
|
|
|
136
138
|
df = df.with_columns(pl.Series(name="x_axis", values=df.map_rows(x_axis_fn)))
|
|
137
139
|
df = df.sort("x_axis")
|
|
138
140
|
|
|
139
|
-
for obs_key,
|
|
141
|
+
for obs_key, obs_df in df.group_by("name"):
|
|
140
142
|
observations.append(
|
|
141
143
|
{
|
|
142
144
|
"name": obs_key[0],
|
|
143
|
-
"values":
|
|
144
|
-
"errors":
|
|
145
|
-
"x_axis":
|
|
145
|
+
"values": obs_df["values"].to_list(),
|
|
146
|
+
"errors": obs_df["errors"].to_list(),
|
|
147
|
+
"x_axis": obs_df["x_axis"].to_list(),
|
|
146
148
|
}
|
|
147
149
|
)
|
|
148
150
|
|
|
@@ -113,27 +113,11 @@ def get_parameter_std_dev(
|
|
|
113
113
|
return Response(content=buffer.getvalue(), media_type="application/octet-stream")
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def _extract_parameter_group_and_key(key: str) -> tuple[str, str] | tuple[None, None]:
|
|
117
|
-
key = key.removeprefix("LOG10_")
|
|
118
|
-
if ":" not in key:
|
|
119
|
-
# Assume all incoming keys are in format group:key for now
|
|
120
|
-
return None, None
|
|
121
|
-
|
|
122
|
-
param_group, param_key = key.split(":", maxsplit=1)
|
|
123
|
-
return param_group, param_key
|
|
124
|
-
|
|
125
|
-
|
|
126
116
|
def data_for_parameter(ensemble: Ensemble, key: str) -> pd.DataFrame:
|
|
127
|
-
group, _ = _extract_parameter_group_and_key(key)
|
|
128
|
-
if group is None:
|
|
129
|
-
logger.warning(
|
|
130
|
-
f"Parameter with key '{key}' does not have a group, "
|
|
131
|
-
"fetching data for all parameters"
|
|
132
|
-
)
|
|
133
117
|
try:
|
|
134
|
-
df = ensemble.
|
|
118
|
+
df = ensemble.load_scalar_keys([key], transformed=True)
|
|
135
119
|
if df.is_empty():
|
|
136
|
-
logger.warning(f"No data found for parameter '{
|
|
120
|
+
logger.warning(f"No data found for parameter '{key}'")
|
|
137
121
|
return pd.DataFrame()
|
|
138
122
|
except KeyError as e:
|
|
139
123
|
logger.error(e)
|
|
@@ -45,7 +45,9 @@ async def get_response(
|
|
|
45
45
|
storage: Storage = DEFAULT_STORAGE,
|
|
46
46
|
ensemble_id: UUID,
|
|
47
47
|
response_key: str,
|
|
48
|
-
filter_on:
|
|
48
|
+
filter_on: Annotated[
|
|
49
|
+
str | None, Query(description="JSON string with filters")
|
|
50
|
+
] = None,
|
|
49
51
|
accept: Annotated[str | None, Header()] = None,
|
|
50
52
|
) -> Response:
|
|
51
53
|
try:
|
|
@@ -96,6 +98,7 @@ async def get_response(
|
|
|
96
98
|
response_to_pandas_x_axis_fns: dict[str, Callable[[tuple[Any, ...]], Any]] = {
|
|
97
99
|
"summary": lambda t: pd.Timestamp(t[2]).isoformat(),
|
|
98
100
|
"gen_data": lambda t: str(t[3]),
|
|
101
|
+
"rft": lambda t: str(t[4]),
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
|
|
@@ -116,7 +119,7 @@ def _extract_response_type_and_key(
|
|
|
116
119
|
|
|
117
120
|
def data_for_response(
|
|
118
121
|
ensemble: Ensemble, key: str, filter_on: dict[str, Any] | None = None
|
|
119
|
-
) -> pd.DataFrame:
|
|
122
|
+
) -> pd.DataFrame | pd.Series:
|
|
120
123
|
response_key, response_type = _extract_response_type_and_key(
|
|
121
124
|
key, ensemble.experiment.response_key_to_response_type
|
|
122
125
|
)
|
|
@@ -147,10 +150,25 @@ def data_for_response(
|
|
|
147
150
|
# This performs the same aggragation by mean of duplicate values
|
|
148
151
|
# as in ert/analysis/_es_update.py
|
|
149
152
|
df = df.groupby(["Date", "Realization"]).mean()
|
|
150
|
-
data = df.
|
|
151
|
-
|
|
153
|
+
data = df.reset_index().pivot_table(
|
|
154
|
+
index="Realization", columns="Date", values=df.columns[0]
|
|
155
|
+
)
|
|
152
156
|
return data.astype(float)
|
|
153
157
|
|
|
158
|
+
if response_type == "rft":
|
|
159
|
+
return (
|
|
160
|
+
ensemble.load_responses(
|
|
161
|
+
response_key,
|
|
162
|
+
tuple(realizations_with_responses),
|
|
163
|
+
)
|
|
164
|
+
.rename({"realization": "Realization"})
|
|
165
|
+
.select(["Realization", "depth", "values"])
|
|
166
|
+
.unique()
|
|
167
|
+
.to_pandas()
|
|
168
|
+
.pivot_table(index="Realization", columns="depth", values="values")
|
|
169
|
+
.reset_index(drop=True)
|
|
170
|
+
)
|
|
171
|
+
|
|
154
172
|
if response_type == "gen_data":
|
|
155
173
|
data = ensemble.load_responses(response_key, tuple(realizations_with_responses))
|
|
156
174
|
|
|
@@ -159,7 +177,7 @@ def data_for_response(
|
|
|
159
177
|
assert "report_step" in filter_on
|
|
160
178
|
report_step = int(filter_on["report_step"])
|
|
161
179
|
vals = data.filter(pl.col("report_step").eq(report_step))
|
|
162
|
-
pivoted = vals.drop("response_key", "report_step").pivot(
|
|
180
|
+
pivoted = vals.drop("response_key", "report_step").pivot( # noqa: PD010
|
|
163
181
|
on="index", values="values"
|
|
164
182
|
)
|
|
165
183
|
data = pivoted.to_pandas().set_index("realization")
|
|
@@ -169,3 +187,4 @@ def data_for_response(
|
|
|
169
187
|
|
|
170
188
|
except (ValueError, KeyError, ColumnNotFoundError):
|
|
171
189
|
return pd.DataFrame()
|
|
190
|
+
return pd.DataFrame()
|
|
@@ -24,6 +24,6 @@ class ExperimentOut(_Experiment):
|
|
|
24
24
|
ensemble_ids: list[UUID]
|
|
25
25
|
priors: Mapping[str, dict[str, Any]]
|
|
26
26
|
userdata: Mapping[str, Any]
|
|
27
|
-
parameters: Mapping[str,
|
|
27
|
+
parameters: Mapping[str, dict[str, Any]]
|
|
28
28
|
responses: Mapping[str, list[dict[str, Any]]]
|
|
29
29
|
observations: Mapping[str, dict[str, list[str]]]
|
ert/data/_measured_data.py
CHANGED
|
@@ -141,13 +141,14 @@ class MeasuredData:
|
|
|
141
141
|
|
|
142
142
|
# Pandas differentiates vs int and str keys.
|
|
143
143
|
# Legacy-wise we use int keys for realizations
|
|
144
|
-
pddf
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
pddf = (
|
|
145
|
+
pddf.rename(
|
|
146
|
+
columns={str(k): int(k) for k in active_realizations},
|
|
147
|
+
)
|
|
148
|
+
.set_index(["observation_key", "key_index"])
|
|
149
|
+
.transpose()
|
|
147
150
|
)
|
|
148
151
|
|
|
149
|
-
pddf = pddf.set_index(["observation_key", "key_index"]).transpose()
|
|
150
|
-
|
|
151
152
|
return pddf
|
|
152
153
|
|
|
153
154
|
|
|
@@ -2,7 +2,13 @@ from ._ensemble import LegacyEnsemble as Ensemble
|
|
|
2
2
|
from ._ensemble import Realization
|
|
3
3
|
from .config import EvaluatorServerConfig
|
|
4
4
|
from .evaluator import EnsembleEvaluator
|
|
5
|
-
from .event import
|
|
5
|
+
from .event import (
|
|
6
|
+
EndEvent,
|
|
7
|
+
FullSnapshotEvent,
|
|
8
|
+
SnapshotUpdateEvent,
|
|
9
|
+
StartEvent,
|
|
10
|
+
WarningEvent,
|
|
11
|
+
)
|
|
6
12
|
from .snapshot import EnsembleSnapshot, FMStepSnapshot, RealizationSnapshot
|
|
7
13
|
|
|
8
14
|
__all__ = [
|
|
@@ -16,5 +22,6 @@ __all__ = [
|
|
|
16
22
|
"Realization",
|
|
17
23
|
"RealizationSnapshot",
|
|
18
24
|
"SnapshotUpdateEvent",
|
|
25
|
+
"StartEvent",
|
|
19
26
|
"WarningEvent",
|
|
20
27
|
]
|
ert/ensemble_evaluator/config.py
CHANGED
|
@@ -27,6 +27,7 @@ class EvaluatorServerConfig:
|
|
|
27
27
|
use_token: bool = True,
|
|
28
28
|
host: str | None = None,
|
|
29
29
|
use_ipc_protocol: bool = True,
|
|
30
|
+
prioritize_private_ip_address: bool = False,
|
|
30
31
|
) -> None:
|
|
31
32
|
self.host: str | None = host
|
|
32
33
|
self.router_port: int | None = None
|
|
@@ -50,7 +51,7 @@ class EvaluatorServerConfig:
|
|
|
50
51
|
if use_ipc_protocol:
|
|
51
52
|
self.uri = f"ipc:///tmp/socket-{uuid.uuid4().hex[:8]}"
|
|
52
53
|
elif self.host is None:
|
|
53
|
-
self.host = get_ip_address()
|
|
54
|
+
self.host = get_ip_address(prioritize_private_ip_address)
|
|
54
55
|
|
|
55
56
|
if use_token:
|
|
56
57
|
self.server_public_key, self.server_secret_key = zmq.curve_keypair()
|