ert 19.0.0rc4__py3-none-any.whl → 20.0.0b0__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/__main__.py +94 -63
- ert/analysis/_es_update.py +11 -14
- ert/config/__init__.py +3 -2
- ert/config/_create_observation_dataframes.py +51 -375
- ert/config/_observations.py +483 -200
- ert/config/_read_summary.py +4 -5
- ert/config/ert_config.py +53 -80
- ert/config/everest_control.py +40 -39
- ert/config/everest_response.py +1 -13
- ert/config/field.py +0 -72
- ert/config/forward_model_step.py +17 -1
- ert/config/gen_data_config.py +14 -17
- ert/config/observation_config_migrations.py +821 -0
- ert/config/parameter_config.py +18 -28
- ert/config/parsing/__init__.py +0 -1
- ert/config/parsing/_parse_zonemap.py +45 -0
- ert/config/parsing/config_keywords.py +1 -1
- ert/config/parsing/config_schema.py +2 -8
- ert/config/parsing/observations_parser.py +2 -0
- ert/config/response_config.py +5 -23
- ert/config/rft_config.py +44 -19
- ert/config/summary_config.py +1 -13
- ert/config/surface_config.py +0 -57
- ert/dark_storage/compute/misfits.py +0 -42
- ert/dark_storage/endpoints/__init__.py +0 -2
- ert/dark_storage/endpoints/experiments.py +2 -5
- ert/dark_storage/json_schema/experiment.py +1 -2
- ert/field_utils/__init__.py +0 -2
- ert/field_utils/field_utils.py +1 -117
- ert/gui/ertwidgets/listeditbox.py +9 -1
- ert/gui/ertwidgets/models/ertsummary.py +20 -6
- ert/gui/ertwidgets/pathchooser.py +9 -1
- ert/gui/ertwidgets/stringbox.py +11 -3
- ert/gui/ertwidgets/textbox.py +10 -3
- ert/gui/ertwidgets/validationsupport.py +19 -1
- ert/gui/main_window.py +11 -6
- ert/gui/simulation/experiment_panel.py +1 -1
- ert/gui/simulation/run_dialog.py +11 -1
- ert/gui/tools/manage_experiments/export_dialog.py +4 -0
- ert/gui/tools/manage_experiments/manage_experiments_panel.py +1 -0
- ert/gui/tools/manage_experiments/storage_info_widget.py +5 -2
- ert/gui/tools/manage_experiments/storage_widget.py +18 -3
- ert/gui/tools/plot/data_type_proxy_model.py +1 -1
- ert/gui/tools/plot/plot_api.py +35 -27
- ert/gui/tools/plot/plot_widget.py +5 -0
- ert/gui/tools/plot/plot_window.py +4 -7
- ert/run_models/ensemble_experiment.py +1 -3
- ert/run_models/ensemble_smoother.py +1 -3
- ert/run_models/everest_run_model.py +12 -13
- ert/run_models/initial_ensemble_run_model.py +19 -22
- ert/run_models/model_factory.py +7 -7
- ert/run_models/multiple_data_assimilation.py +1 -3
- ert/sample_prior.py +12 -14
- ert/services/__init__.py +7 -3
- ert/services/_storage_main.py +59 -22
- ert/services/ert_server.py +186 -24
- ert/shared/version.py +3 -3
- ert/storage/local_ensemble.py +46 -115
- ert/storage/local_experiment.py +0 -16
- ert/utils/__init__.py +20 -0
- ert/warnings/specific_warning_handler.py +3 -2
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/METADATA +4 -51
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/RECORD +75 -80
- everest/bin/everest_script.py +5 -5
- everest/bin/kill_script.py +2 -2
- everest/bin/monitor_script.py +2 -2
- everest/bin/utils.py +4 -4
- everest/detached/everserver.py +6 -6
- everest/gui/everest_client.py +0 -6
- everest/gui/main_window.py +2 -2
- everest/util/__init__.py +1 -19
- ert/dark_storage/compute/__init__.py +0 -0
- ert/dark_storage/endpoints/compute/__init__.py +0 -0
- ert/dark_storage/endpoints/compute/misfits.py +0 -95
- ert/services/_base_service.py +0 -387
- ert/services/webviz_ert_service.py +0 -20
- ert/shared/storage/command.py +0 -38
- ert/shared/storage/extraction.py +0 -42
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/WHEEL +0 -0
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/entry_points.txt +0 -0
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/licenses/COPYING +0 -0
- {ert-19.0.0rc4.dist-info → ert-20.0.0b0.dist-info}/top_level.txt +0 -0
ert/config/parameter_config.py
CHANGED
|
@@ -126,35 +126,28 @@ class ParameterConfig(BaseModel):
|
|
|
126
126
|
def transform_data(self) -> Callable[[float], float]:
|
|
127
127
|
return lambda x: x
|
|
128
128
|
|
|
129
|
-
def
|
|
130
|
-
self,
|
|
131
|
-
global_seed: str,
|
|
132
|
-
realization: int,
|
|
129
|
+
def sample_values(
|
|
130
|
+
self, global_seed: str, active_realizations: list[int], num_realizations: int
|
|
133
131
|
) -> npt.NDArray[np.double]:
|
|
134
132
|
"""
|
|
135
|
-
Generate
|
|
133
|
+
Generate reproducible standard-normal samples for active realizations.
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
For this parameter (identified by self.group_name and self.name), a random
|
|
136
|
+
sampling of size `num_realizations` is constructed using an RNG
|
|
137
|
+
seeded from `global_seed` and the parameter name. The entries at the
|
|
138
|
+
indices specified by `active_realizations` are then returned.
|
|
141
139
|
|
|
142
140
|
Parameters:
|
|
143
|
-
- global_seed (str): A global seed string used for RNG seed generation to
|
|
144
|
-
reproducibility across runs.
|
|
145
|
-
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
- global_seed (str): A global seed string used for RNG seed generation to
|
|
142
|
+
ensure reproducibility across runs.
|
|
143
|
+
- active_realizations (list[int]): indices of the realizations
|
|
144
|
+
to select from the sampling vector; each must satisfy 0 <= i < num_realizations.
|
|
145
|
+
- num_realizations (int): Total number of realizations. Assures stable sampling
|
|
146
|
+
for a given global_seed regardless of currently active realizations.
|
|
148
147
|
|
|
149
148
|
Returns:
|
|
150
|
-
- npt.NDArray[np.double]:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
Note:
|
|
154
|
-
The method uses SHA-256 for hash generation and numpy's default random number
|
|
155
|
-
generator for sampling. The RNG state is advanced to the 'realization' point
|
|
156
|
-
before generating a single sample, enhancing efficiency by avoiding the
|
|
157
|
-
generation of large, unused sample sets.
|
|
149
|
+
- npt.NDArray[np.double]: Array of shape (len(active_realizations),
|
|
150
|
+
containing sample values, one for each `active_realization`.
|
|
158
151
|
"""
|
|
159
152
|
key_hash = sha256(
|
|
160
153
|
global_seed.encode("utf-8") + f"{self.group_name}:{self.name}".encode()
|
|
@@ -162,9 +155,6 @@ class ParameterConfig(BaseModel):
|
|
|
162
155
|
seed = np.frombuffer(key_hash.digest(), dtype="uint32")
|
|
163
156
|
rng = np.random.default_rng(seed)
|
|
164
157
|
|
|
165
|
-
#
|
|
166
|
-
rng.standard_normal(
|
|
167
|
-
|
|
168
|
-
# Generate a single sample
|
|
169
|
-
value = rng.standard_normal(1)
|
|
170
|
-
return np.array([value[0]])
|
|
158
|
+
# Generate samples for all active realizations
|
|
159
|
+
all_values = rng.standard_normal(num_realizations)
|
|
160
|
+
return all_values[active_realizations]
|
ert/config/parsing/__init__.py
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from .config_errors import ConfigValidationError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def parse_zonemap(filename: str, content: str) -> dict[int, list[str]]:
|
|
5
|
+
"""A zonemap is a map from a simulation grids layers to a list of zone names
|
|
6
|
+
that the k-layers belongs to.
|
|
7
|
+
|
|
8
|
+
Note that the map uses 1-indexing of layers.
|
|
9
|
+
"""
|
|
10
|
+
zones_at_k_value: dict[int, list[str]] = {}
|
|
11
|
+
|
|
12
|
+
base_err_msg = "On Line {line_number} in the ZONEMAP file: "
|
|
13
|
+
for idx, line in enumerate(content.splitlines()):
|
|
14
|
+
line_number = idx + 1
|
|
15
|
+
zonemap_line = _strip_comments(line).split()
|
|
16
|
+
|
|
17
|
+
if not zonemap_line:
|
|
18
|
+
continue
|
|
19
|
+
|
|
20
|
+
if len(zonemap_line) < 2:
|
|
21
|
+
raise ConfigValidationError.with_context(
|
|
22
|
+
"Number of zonenames must be 1 or more.",
|
|
23
|
+
filename,
|
|
24
|
+
)
|
|
25
|
+
try:
|
|
26
|
+
k = int(zonemap_line[0])
|
|
27
|
+
except ValueError as err:
|
|
28
|
+
raise ConfigValidationError.with_context(
|
|
29
|
+
base_err_msg.format(line_number=line_number)
|
|
30
|
+
+ f"k must be an integer, was {zonemap_line[0]}.",
|
|
31
|
+
filename,
|
|
32
|
+
) from err
|
|
33
|
+
if k <= 0:
|
|
34
|
+
raise ConfigValidationError.with_context(
|
|
35
|
+
base_err_msg.format(line_number=line_number)
|
|
36
|
+
+ "k must be at least 1. Layers are 1-indexed.",
|
|
37
|
+
filename,
|
|
38
|
+
)
|
|
39
|
+
zones_at_k_value[k] = [zone.strip() for zone in zonemap_line[1:]]
|
|
40
|
+
|
|
41
|
+
return zones_at_k_value
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _strip_comments(line: str) -> str:
|
|
45
|
+
return line.partition("--")[0].rstrip()
|
|
@@ -31,6 +31,7 @@ class ConfigKeys(StrEnum):
|
|
|
31
31
|
NUM_REALIZATIONS = "NUM_REALIZATIONS"
|
|
32
32
|
MIN_REALIZATIONS = "MIN_REALIZATIONS"
|
|
33
33
|
OBS_CONFIG = "OBS_CONFIG"
|
|
34
|
+
ZONEMAP = "ZONEMAP"
|
|
34
35
|
QUEUE_SYSTEM = "QUEUE_SYSTEM"
|
|
35
36
|
QUEUE_OPTION = "QUEUE_OPTION"
|
|
36
37
|
HOOK_WORKFLOW = "HOOK_WORKFLOW"
|
|
@@ -56,7 +57,6 @@ class ConfigKeys(StrEnum):
|
|
|
56
57
|
REALIZATION_MEMORY = "REALIZATION_MEMORY"
|
|
57
58
|
SUBMIT_SLEEP = "SUBMIT_SLEEP"
|
|
58
59
|
MAX_RUNNING = "MAX_RUNNING"
|
|
59
|
-
PRIORITIZE_PRIVATE_IP_ADDRESS = "PRIORITIZE_PRIVATE_IP_ADDRESS"
|
|
60
60
|
|
|
61
61
|
def __repr__(self) -> str:
|
|
62
62
|
return f"{self.value!r}"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from ._parse_zonemap import parse_zonemap
|
|
1
2
|
from .config_dict import ConfigDict
|
|
2
3
|
from .config_keywords import ConfigKeys
|
|
3
4
|
from .config_schema_deprecations import deprecated_keywords_list
|
|
@@ -126,13 +127,6 @@ def hook_workflow_keyword() -> SchemaItem:
|
|
|
126
127
|
)
|
|
127
128
|
|
|
128
129
|
|
|
129
|
-
def prioritize_private_ip_address_keyword() -> SchemaItem:
|
|
130
|
-
return SchemaItem(
|
|
131
|
-
kw=ConfigKeys.PRIORITIZE_PRIVATE_IP_ADDRESS,
|
|
132
|
-
type_map=[SchemaItemType.BOOL],
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
|
|
136
130
|
def set_env_keyword() -> SchemaItem:
|
|
137
131
|
# You can set environment variables which will be applied to the run-time
|
|
138
132
|
# environment.
|
|
@@ -340,6 +334,7 @@ def init_user_config_schema() -> ConfigSchemaDict:
|
|
|
340
334
|
existing_path_inline_keyword(
|
|
341
335
|
ConfigKeys.OBS_CONFIG, parser=lambda f, c: parse_observations(c, f)
|
|
342
336
|
),
|
|
337
|
+
existing_path_inline_keyword(ConfigKeys.ZONEMAP, parser=parse_zonemap),
|
|
343
338
|
existing_path_inline_keyword(ConfigKeys.TIME_MAP),
|
|
344
339
|
single_arg_keyword(ConfigKeys.GEN_KW_EXPORT_NAME),
|
|
345
340
|
history_source_keyword(),
|
|
@@ -356,7 +351,6 @@ def init_user_config_schema() -> ConfigSchemaDict:
|
|
|
356
351
|
install_job_keyword(),
|
|
357
352
|
install_job_directory_keyword(),
|
|
358
353
|
hook_workflow_keyword(),
|
|
359
|
-
prioritize_private_ip_address_keyword(),
|
|
360
354
|
]:
|
|
361
355
|
schema[item.kw] = item
|
|
362
356
|
if item.kw in ConfigAliases:
|
|
@@ -19,6 +19,7 @@ class ObservationType(StrEnum):
|
|
|
19
19
|
SUMMARY = "SUMMARY_OBSERVATION"
|
|
20
20
|
GENERAL = "GENERAL_OBSERVATION"
|
|
21
21
|
RFT = "RFT_OBSERVATION"
|
|
22
|
+
BREAKTHROUGH = "BREAKTHROUGH_OBSERVATION"
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
ObservationDict = dict[str, Any]
|
|
@@ -127,6 +128,7 @@ observations_parser = Lark(
|
|
|
127
128
|
| "SUMMARY_OBSERVATION"
|
|
128
129
|
| "GENERAL_OBSERVATION"
|
|
129
130
|
| "RFT_OBSERVATION"
|
|
131
|
+
| "BREAKTHROUGH_OBSERVATION"
|
|
130
132
|
type: TYPE
|
|
131
133
|
?value: object
|
|
132
134
|
| STRING
|
ert/config/response_config.py
CHANGED
|
@@ -14,35 +14,12 @@ class InvalidResponseFile(Exception):
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class ResponseMetadata(BaseModel):
|
|
18
|
-
response_type: str
|
|
19
|
-
response_key: str
|
|
20
|
-
finalized: bool
|
|
21
|
-
filter_on: dict[str, list[Any]] | None = Field(
|
|
22
|
-
default=None,
|
|
23
|
-
description="""
|
|
24
|
-
Holds information about which columns the response can be filtered on.
|
|
25
|
-
For example, for gen data, { "report_step": [0, 199, 299] } indicates
|
|
26
|
-
that we can filter the response by report step with the potential values
|
|
27
|
-
[0, 199, 299].
|
|
28
|
-
""",
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
17
|
class ResponseConfig(BaseModel):
|
|
33
18
|
type: str
|
|
34
19
|
input_files: list[str] = Field(default_factory=list)
|
|
35
20
|
keys: list[str] = Field(default_factory=list)
|
|
36
21
|
has_finalized_keys: bool = False
|
|
37
22
|
|
|
38
|
-
@property
|
|
39
|
-
@abstractmethod
|
|
40
|
-
def metadata(self) -> list[ResponseMetadata]:
|
|
41
|
-
"""
|
|
42
|
-
Returns metadata describing this response
|
|
43
|
-
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
23
|
@abstractmethod
|
|
47
24
|
def read_from_file(self, run_path: str, iens: int, iter_: int) -> pl.DataFrame:
|
|
48
25
|
"""Reads the data for the response from run_path.
|
|
@@ -76,3 +53,8 @@ class ResponseConfig(BaseModel):
|
|
|
76
53
|
def display_column(cls, value: Any, column_name: str) -> str:
|
|
77
54
|
"""Formats a value to a user-friendly displayable format."""
|
|
78
55
|
return str(value)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def filter_on(self) -> dict[str, dict[str, list[int]]] | None:
|
|
59
|
+
"""Optional filters for this response."""
|
|
60
|
+
return None
|
ert/config/rft_config.py
CHANGED
|
@@ -5,8 +5,9 @@ import fnmatch
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
|
+
import warnings
|
|
8
9
|
from collections import defaultdict
|
|
9
|
-
from typing import IO, Any, Literal
|
|
10
|
+
from typing import IO, Any, Literal, TypeAlias
|
|
10
11
|
|
|
11
12
|
import numpy as np
|
|
12
13
|
import numpy.typing as npt
|
|
@@ -15,32 +16,27 @@ from pydantic import Field
|
|
|
15
16
|
from resfo_utilities import CornerpointGrid, InvalidRFTError, RFTReader
|
|
16
17
|
|
|
17
18
|
from ert.substitutions import substitute_runpath_name
|
|
19
|
+
from ert.warnings import PostSimulationWarning
|
|
18
20
|
|
|
19
21
|
from .parsing import ConfigDict, ConfigKeys, ConfigValidationError, ConfigWarning
|
|
20
|
-
from .response_config import InvalidResponseFile, ResponseConfig
|
|
22
|
+
from .response_config import InvalidResponseFile, ResponseConfig
|
|
21
23
|
from .responses_index import responses_index
|
|
22
24
|
|
|
23
25
|
logger = logging.getLogger(__name__)
|
|
24
26
|
|
|
25
27
|
|
|
28
|
+
Point: TypeAlias = tuple[float, float, float]
|
|
29
|
+
GridIndex: TypeAlias = tuple[int, int, int]
|
|
30
|
+
ZoneName: TypeAlias = str
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
class RFTConfig(ResponseConfig):
|
|
27
34
|
type: Literal["rft"] = "rft"
|
|
28
35
|
name: str = "rft"
|
|
29
36
|
has_finalized_keys: bool = False
|
|
30
37
|
data_to_read: dict[str, dict[str, list[str]]] = Field(default_factory=dict)
|
|
31
|
-
locations: list[tuple[
|
|
32
|
-
|
|
33
|
-
@property
|
|
34
|
-
def metadata(self) -> list[ResponseMetadata]:
|
|
35
|
-
return [
|
|
36
|
-
ResponseMetadata(
|
|
37
|
-
response_type=self.name,
|
|
38
|
-
response_key=response_key,
|
|
39
|
-
filter_on=None,
|
|
40
|
-
finalized=self.has_finalized_keys,
|
|
41
|
-
)
|
|
42
|
-
for response_key in self.keys
|
|
43
|
-
]
|
|
38
|
+
locations: list[Point | tuple[Point, ZoneName]] = Field(default_factory=list)
|
|
39
|
+
zonemap: dict[int, list[ZoneName]] = Field(default_factory=dict)
|
|
44
40
|
|
|
45
41
|
@property
|
|
46
42
|
def expected_input_files(self) -> list[str]:
|
|
@@ -55,11 +51,11 @@ class RFTConfig(ResponseConfig):
|
|
|
55
51
|
|
|
56
52
|
def _find_indices(
|
|
57
53
|
self, egrid_file: str | os.PathLike[str] | IO[Any]
|
|
58
|
-
) -> dict[
|
|
54
|
+
) -> dict[GridIndex | None, set[Point | tuple[Point, ZoneName]]]:
|
|
59
55
|
indices = defaultdict(set)
|
|
60
56
|
for a, b in zip(
|
|
61
57
|
CornerpointGrid.read_egrid(egrid_file).find_cell_containing_point(
|
|
62
|
-
self.locations
|
|
58
|
+
[loc[0] if isinstance(loc[1], str) else loc for loc in self.locations]
|
|
63
59
|
),
|
|
64
60
|
self.locations,
|
|
65
61
|
strict=True,
|
|
@@ -67,6 +63,34 @@ class RFTConfig(ResponseConfig):
|
|
|
67
63
|
indices[a].add(b)
|
|
68
64
|
return indices
|
|
69
65
|
|
|
66
|
+
def _filter_zones(
|
|
67
|
+
self,
|
|
68
|
+
indices: dict[GridIndex | None, set[Point | tuple[Point, ZoneName]]],
|
|
69
|
+
iens: int,
|
|
70
|
+
iter_: int,
|
|
71
|
+
) -> dict[GridIndex | None, set[Point]]:
|
|
72
|
+
for idx, locs in indices.items():
|
|
73
|
+
if idx is not None:
|
|
74
|
+
for loc in list(locs):
|
|
75
|
+
if isinstance(loc[1], str):
|
|
76
|
+
zone = loc[1]
|
|
77
|
+
# zonemap is 1-indexed so +1
|
|
78
|
+
if zone not in self.zonemap.get(idx[-1] + 1, []):
|
|
79
|
+
warnings.warn(
|
|
80
|
+
PostSimulationWarning(
|
|
81
|
+
f"An RFT observation with location {loc[0]}, "
|
|
82
|
+
f"in iteration {iter_}, realization {iens} did "
|
|
83
|
+
f"not match expected zone {zone}. The observation "
|
|
84
|
+
"was deactivated",
|
|
85
|
+
),
|
|
86
|
+
stacklevel=2,
|
|
87
|
+
)
|
|
88
|
+
locs.remove(loc)
|
|
89
|
+
return {
|
|
90
|
+
k: {v[0] if isinstance(v[1], str) else v for v in vs}
|
|
91
|
+
for k, vs in indices.items()
|
|
92
|
+
}
|
|
93
|
+
|
|
70
94
|
def read_from_file(self, run_path: str, iens: int, iter_: int) -> pl.DataFrame:
|
|
71
95
|
filename = substitute_runpath_name(self.input_files[0], iens, iter_)
|
|
72
96
|
if filename.upper().endswith(".DATA"):
|
|
@@ -83,7 +107,7 @@ class RFTConfig(ResponseConfig):
|
|
|
83
107
|
)
|
|
84
108
|
indices = {}
|
|
85
109
|
if self.locations:
|
|
86
|
-
indices = self._find_indices(grid_filename)
|
|
110
|
+
indices = self._filter_zones(self._find_indices(grid_filename), iens, iter_)
|
|
87
111
|
if None in indices:
|
|
88
112
|
raise InvalidResponseFile(
|
|
89
113
|
f"Did not find grid coordinate for location(s) {indices[None]}"
|
|
@@ -194,7 +218,7 @@ class RFTConfig(ResponseConfig):
|
|
|
194
218
|
.explode("location")
|
|
195
219
|
for (well, time), inner_dict in fetched.items()
|
|
196
220
|
for prop, vals in inner_dict.items()
|
|
197
|
-
if prop != "DEPTH"
|
|
221
|
+
if prop != "DEPTH" and len(vals) > 0
|
|
198
222
|
]
|
|
199
223
|
)
|
|
200
224
|
except KeyError as err:
|
|
@@ -267,6 +291,7 @@ class RFTConfig(ResponseConfig):
|
|
|
267
291
|
input_files=[eclbase.replace("%d", "<IENS>")],
|
|
268
292
|
keys=keys,
|
|
269
293
|
data_to_read=data_to_read,
|
|
294
|
+
zonemap=config_dict.get(ConfigKeys.ZONEMAP, ("", {}))[1],
|
|
270
295
|
)
|
|
271
296
|
|
|
272
297
|
return None
|
ert/config/summary_config.py
CHANGED
|
@@ -11,7 +11,7 @@ from ert.substitutions import substitute_runpath_name
|
|
|
11
11
|
from ._read_summary import read_summary
|
|
12
12
|
from .parsing import ConfigDict, ConfigKeys
|
|
13
13
|
from .parsing.config_errors import ConfigValidationError, ConfigWarning
|
|
14
|
-
from .response_config import InvalidResponseFile, ResponseConfig
|
|
14
|
+
from .response_config import InvalidResponseFile, ResponseConfig
|
|
15
15
|
from .responses_index import responses_index
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
@@ -21,18 +21,6 @@ class SummaryConfig(ResponseConfig):
|
|
|
21
21
|
type: Literal["summary"] = "summary"
|
|
22
22
|
has_finalized_keys: bool = False
|
|
23
23
|
|
|
24
|
-
@property
|
|
25
|
-
def metadata(self) -> list[ResponseMetadata]:
|
|
26
|
-
return [
|
|
27
|
-
ResponseMetadata(
|
|
28
|
-
response_type=self.type,
|
|
29
|
-
response_key=response_key,
|
|
30
|
-
filter_on=None,
|
|
31
|
-
finalized=self.has_finalized_keys,
|
|
32
|
-
)
|
|
33
|
-
for response_key in self.keys
|
|
34
|
-
]
|
|
35
|
-
|
|
36
24
|
@property
|
|
37
25
|
def expected_input_files(self) -> list[str]:
|
|
38
26
|
base = self.input_files[0]
|
ert/config/surface_config.py
CHANGED
|
@@ -10,11 +10,6 @@ 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
|
-
)
|
|
18
13
|
from ert.substitutions import substitute_runpath_name
|
|
19
14
|
|
|
20
15
|
from ._str_to_bool import str_to_bool
|
|
@@ -239,55 +234,3 @@ class SurfaceConfig(ParameterConfig):
|
|
|
239
234
|
this flattening process"""
|
|
240
235
|
|
|
241
236
|
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
|
-
)
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import numpy.typing as npt
|
|
5
|
-
import pandas as pd
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _calculate_signed_chi_squared_misfit(
|
|
9
|
-
obs_value: npt.NDArray[np.float64],
|
|
10
|
-
response_value: npt.NDArray[np.float64],
|
|
11
|
-
obs_std: npt.NDArray[np.float64],
|
|
12
|
-
) -> list[float]:
|
|
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()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def calculate_signed_chi_squared_misfits(
|
|
20
|
-
reponses_dict: Mapping[int, pd.DataFrame],
|
|
21
|
-
observation: pd.DataFrame,
|
|
22
|
-
summary_misfits: bool = False,
|
|
23
|
-
) -> pd.DataFrame:
|
|
24
|
-
"""
|
|
25
|
-
Compute misfits from reponses_dict (real_id, values in dataframe)
|
|
26
|
-
and observation
|
|
27
|
-
"""
|
|
28
|
-
misfits_dict = {}
|
|
29
|
-
for realization_index in reponses_dict:
|
|
30
|
-
misfits_dict[realization_index] = _calculate_signed_chi_squared_misfit(
|
|
31
|
-
observation["values"],
|
|
32
|
-
reponses_dict[realization_index]
|
|
33
|
-
.loc[:, observation.index]
|
|
34
|
-
.to_numpy()
|
|
35
|
-
.flatten(),
|
|
36
|
-
observation["errors"],
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
df = pd.DataFrame(data=misfits_dict, index=observation.index)
|
|
40
|
-
if summary_misfits:
|
|
41
|
-
df = pd.DataFrame([df.abs().sum(axis=0)], columns=df.columns, index=[0])
|
|
42
|
-
return df.T
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
2
|
|
|
3
|
-
from .compute.misfits import router as misfits_router
|
|
4
3
|
from .ensembles import router as ensembles_router
|
|
5
4
|
from .experiment_server import router as experiment_server_router
|
|
6
5
|
from .experiments import router as experiments_router
|
|
@@ -15,7 +14,6 @@ router.include_router(experiments_router)
|
|
|
15
14
|
router.include_router(ensembles_router)
|
|
16
15
|
router.include_router(observations_router)
|
|
17
16
|
router.include_router(updates_router)
|
|
18
|
-
router.include_router(misfits_router)
|
|
19
17
|
router.include_router(parameters_router)
|
|
20
18
|
router.include_router(responses_router)
|
|
21
19
|
router.include_router(experiment_server_router)
|
|
@@ -6,7 +6,6 @@ from fastapi import APIRouter, Body, Depends, HTTPException
|
|
|
6
6
|
from ert.config import SurfaceConfig
|
|
7
7
|
from ert.dark_storage import json_schema as js
|
|
8
8
|
from ert.dark_storage.common import get_storage
|
|
9
|
-
from ert.shared.storage.extraction import create_priors
|
|
10
9
|
from ert.storage import Storage
|
|
11
10
|
|
|
12
11
|
router = APIRouter(tags=["experiment"])
|
|
@@ -26,7 +25,6 @@ def get_experiments(
|
|
|
26
25
|
id=experiment.id,
|
|
27
26
|
name=experiment.name,
|
|
28
27
|
ensemble_ids=[ens.id for ens in experiment.ensembles],
|
|
29
|
-
priors=create_priors(experiment),
|
|
30
28
|
userdata={},
|
|
31
29
|
parameters={
|
|
32
30
|
group: config.model_dump()
|
|
@@ -34,7 +32,7 @@ def get_experiments(
|
|
|
34
32
|
if not isinstance(config, SurfaceConfig)
|
|
35
33
|
},
|
|
36
34
|
responses={
|
|
37
|
-
response_type:
|
|
35
|
+
response_type: config.model_dump()
|
|
38
36
|
for response_type, config in experiment.response_configuration.items()
|
|
39
37
|
},
|
|
40
38
|
observations=experiment.response_key_to_observation_key,
|
|
@@ -62,14 +60,13 @@ def get_experiment_by_id(
|
|
|
62
60
|
name=experiment.name,
|
|
63
61
|
id=experiment.id,
|
|
64
62
|
ensemble_ids=[ens.id for ens in experiment.ensembles],
|
|
65
|
-
priors=create_priors(experiment),
|
|
66
63
|
userdata={},
|
|
67
64
|
parameters={
|
|
68
65
|
group: config.model_dump()
|
|
69
66
|
for group, config in experiment.parameter_configuration.items()
|
|
70
67
|
},
|
|
71
68
|
responses={
|
|
72
|
-
response_type:
|
|
69
|
+
response_type: config.model_dump()
|
|
73
70
|
for response_type, config in experiment.response_configuration.items()
|
|
74
71
|
},
|
|
75
72
|
observations=experiment.response_key_to_observation_key,
|
|
@@ -22,8 +22,7 @@ class ExperimentIn(_Experiment):
|
|
|
22
22
|
class ExperimentOut(_Experiment):
|
|
23
23
|
id: UUID
|
|
24
24
|
ensemble_ids: list[UUID]
|
|
25
|
-
priors: Mapping[str, dict[str, Any]]
|
|
26
25
|
userdata: Mapping[str, Any]
|
|
27
26
|
parameters: Mapping[str, dict[str, Any]]
|
|
28
|
-
responses: Mapping[str,
|
|
27
|
+
responses: Mapping[str, dict[str, Any]]
|
|
29
28
|
observations: Mapping[str, dict[str, list[str]]]
|
ert/field_utils/__init__.py
CHANGED
|
@@ -4,7 +4,6 @@ from .field_file_format import FieldFileFormat
|
|
|
4
4
|
from .field_utils import (
|
|
5
5
|
ErtboxParameters,
|
|
6
6
|
Shape,
|
|
7
|
-
calc_rho_for_2d_grid_layer,
|
|
8
7
|
calculate_ertbox_parameters,
|
|
9
8
|
get_shape,
|
|
10
9
|
localization_scaling_function,
|
|
@@ -19,7 +18,6 @@ __all__ = [
|
|
|
19
18
|
"ErtboxParameters",
|
|
20
19
|
"FieldFileFormat",
|
|
21
20
|
"Shape",
|
|
22
|
-
"calc_rho_for_2d_grid_layer",
|
|
23
21
|
"calculate_ertbox_parameters",
|
|
24
22
|
"get_shape",
|
|
25
23
|
"localization_scaling_function",
|