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/field.py
CHANGED
|
@@ -3,32 +3,33 @@ from __future__ import annotations
|
|
|
3
3
|
import itertools
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
-
from collections.abc import Iterator
|
|
7
|
-
from functools import cached_property
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING, Any, Literal, Self, cast, overload
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Final, Literal, Self, cast, overload
|
|
10
9
|
|
|
11
10
|
import networkx as nx
|
|
12
11
|
import numpy as np
|
|
13
12
|
import xarray as xr
|
|
14
|
-
import xtgeo
|
|
13
|
+
import xtgeo
|
|
15
14
|
from pydantic import field_serializer
|
|
16
15
|
|
|
17
16
|
from ert.field_utils import (
|
|
18
17
|
ErtboxParameters,
|
|
19
18
|
FieldFileFormat,
|
|
20
19
|
Shape,
|
|
20
|
+
calc_rho_for_2d_grid_layer,
|
|
21
21
|
calculate_ertbox_parameters,
|
|
22
22
|
get_shape,
|
|
23
23
|
read_field,
|
|
24
|
-
read_mask,
|
|
25
24
|
save_field,
|
|
25
|
+
transform_local_ellipse_angle_to_local_coords,
|
|
26
|
+
transform_positions_to_local_field_coordinates,
|
|
26
27
|
)
|
|
27
28
|
from ert.substitutions import substitute_runpath_name
|
|
28
29
|
from ert.utils import log_duration
|
|
29
30
|
|
|
30
31
|
from ._str_to_bool import str_to_bool
|
|
31
|
-
from .parameter_config import ParameterConfig
|
|
32
|
+
from .parameter_config import ParameterConfig
|
|
32
33
|
from .parsing import ConfigValidationError, ConfigWarning
|
|
33
34
|
|
|
34
35
|
if TYPE_CHECKING:
|
|
@@ -67,32 +68,9 @@ def create_flattened_cube_graph(px: int, py: int, pz: int) -> nx.Graph[int]:
|
|
|
67
68
|
return G
|
|
68
69
|
|
|
69
70
|
|
|
70
|
-
def adjust_graph_for_masking(
|
|
71
|
-
G: nx.Graph[int], mask: npt.NDArray[np.bool_]
|
|
72
|
-
) -> nx.Graph[int]:
|
|
73
|
-
"""
|
|
74
|
-
Adjust the graph G according to the masking indices.
|
|
75
|
-
Removes nodes specified by the mask and relabels the remaining nodes
|
|
76
|
-
to have consecutive labels from 0 to G.number_of_nodes - 1.
|
|
77
|
-
Parameters:
|
|
78
|
-
- G: The graph to adjust
|
|
79
|
-
- mask: Boolean mask flattened array
|
|
80
|
-
Returns:
|
|
81
|
-
- The adjusted graph
|
|
82
|
-
"""
|
|
83
|
-
# Step 1: Remove nodes specified by mask_indices
|
|
84
|
-
mask_indices = np.where(mask)[0]
|
|
85
|
-
G.remove_nodes_from(mask_indices)
|
|
86
|
-
|
|
87
|
-
# Step 2: Relabel remaining nodes to 0, 1, 2, ..., G.number_of_nodes - 1
|
|
88
|
-
new_labels = {old_label: new_label for new_label, old_label in enumerate(G.nodes())}
|
|
89
|
-
G = nx.relabel_nodes(G, new_labels, copy=True)
|
|
90
|
-
|
|
91
|
-
return G
|
|
92
|
-
|
|
93
|
-
|
|
94
71
|
class Field(ParameterConfig):
|
|
95
72
|
type: Literal["field"] = "field"
|
|
73
|
+
dimensionality: Literal[3] = 3
|
|
96
74
|
ertbox_params: ErtboxParameters
|
|
97
75
|
file_format: FieldFileFormat
|
|
98
76
|
output_transformation: str | None
|
|
@@ -102,31 +80,15 @@ class Field(ParameterConfig):
|
|
|
102
80
|
forward_init_file: str
|
|
103
81
|
output_file: Path
|
|
104
82
|
grid_file: str
|
|
105
|
-
mask_file: Path | None = None
|
|
106
83
|
|
|
107
84
|
@field_serializer("output_file")
|
|
108
85
|
def serialize_output_file(self, path: Path) -> str:
|
|
109
86
|
return str(path)
|
|
110
87
|
|
|
111
|
-
@field_serializer("mask_file")
|
|
112
|
-
def serialize_mask_file(self, path: Path | None) -> str | None:
|
|
113
|
-
return str(path) if path is not None else None
|
|
114
|
-
|
|
115
88
|
@property
|
|
116
89
|
def parameter_keys(self) -> list[str]:
|
|
117
90
|
return []
|
|
118
91
|
|
|
119
|
-
@property
|
|
120
|
-
def metadata(self) -> list[ParameterMetadata]:
|
|
121
|
-
return [
|
|
122
|
-
ParameterMetadata(
|
|
123
|
-
key=self.name,
|
|
124
|
-
transformation=self.output_transformation,
|
|
125
|
-
dimensionality=3,
|
|
126
|
-
userdata={"data_origin": "FIELD", "ertbox_params": self.ertbox_params},
|
|
127
|
-
)
|
|
128
|
-
]
|
|
129
|
-
|
|
130
92
|
@classmethod
|
|
131
93
|
def from_config_list(
|
|
132
94
|
cls,
|
|
@@ -239,11 +201,7 @@ class Field(ParameterConfig):
|
|
|
239
201
|
)
|
|
240
202
|
|
|
241
203
|
def __len__(self) -> int:
|
|
242
|
-
|
|
243
|
-
return self.ertbox_params.nx * self.ertbox_params.ny * self.ertbox_params.nz
|
|
244
|
-
|
|
245
|
-
# Uses int() to convert to standard python int for mypy
|
|
246
|
-
return int(np.size(self.mask) - np.count_nonzero(self.mask))
|
|
204
|
+
return self.ertbox_params.nx * self.ertbox_params.ny * self.ertbox_params.nz
|
|
247
205
|
|
|
248
206
|
@log_duration(_logger, custom_name="load_field")
|
|
249
207
|
def read_from_runpath(
|
|
@@ -258,7 +216,6 @@ class Field(ParameterConfig):
|
|
|
258
216
|
read_field(
|
|
259
217
|
run_path / file_name,
|
|
260
218
|
self.name,
|
|
261
|
-
self.mask,
|
|
262
219
|
Shape(
|
|
263
220
|
self.ertbox_params.nx,
|
|
264
221
|
self.ertbox_params.ny,
|
|
@@ -294,16 +251,15 @@ class Field(ParameterConfig):
|
|
|
294
251
|
from_data: npt.NDArray[np.float64],
|
|
295
252
|
iens_active_index: npt.NDArray[np.int_],
|
|
296
253
|
) -> Iterator[tuple[int, xr.Dataset]]:
|
|
254
|
+
dim_nx, dim_ny, dim_nz = (
|
|
255
|
+
self.ertbox_params.nx,
|
|
256
|
+
self.ertbox_params.ny,
|
|
257
|
+
self.ertbox_params.nz,
|
|
258
|
+
)
|
|
259
|
+
|
|
297
260
|
for i, realization in enumerate(iens_active_index):
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
mask=self.mask,
|
|
301
|
-
fill_value=np.nan,
|
|
302
|
-
dtype=from_data.dtype,
|
|
303
|
-
)
|
|
304
|
-
ma[~ma.mask] = from_data[:, i]
|
|
305
|
-
ma = ma.reshape(self.mask.shape) # type: ignore
|
|
306
|
-
ds = xr.Dataset({"values": (["x", "y", "z"], ma.filled())})
|
|
261
|
+
values = from_data[:, i].reshape((dim_nx, dim_ny, dim_nz))
|
|
262
|
+
ds = xr.Dataset({"values": (["x", "y", "z"], values)})
|
|
307
263
|
yield int(realization), ds
|
|
308
264
|
|
|
309
265
|
def load_parameters(
|
|
@@ -314,7 +270,7 @@ class Field(ParameterConfig):
|
|
|
314
270
|
ensemble_size = len(ds.realizations)
|
|
315
271
|
da = xr.DataArray(
|
|
316
272
|
[
|
|
317
|
-
np.ma.MaskedArray(data=d
|
|
273
|
+
np.ma.MaskedArray(data=d).compressed()
|
|
318
274
|
for d in ds["values"].values.reshape(ensemble_size, -1)
|
|
319
275
|
]
|
|
320
276
|
)
|
|
@@ -328,7 +284,7 @@ class Field(ParameterConfig):
|
|
|
328
284
|
def _transform_data(
|
|
329
285
|
self, data_array: xr.DataArray
|
|
330
286
|
) -> np.ma.MaskedArray[Any, np.dtype[np.float32]]:
|
|
331
|
-
return np.ma.MaskedArray(
|
|
287
|
+
return np.ma.MaskedArray(
|
|
332
288
|
_field_truncate(
|
|
333
289
|
field_transform(
|
|
334
290
|
data_array,
|
|
@@ -337,31 +293,18 @@ class Field(ParameterConfig):
|
|
|
337
293
|
self.truncation_min,
|
|
338
294
|
self.truncation_max,
|
|
339
295
|
),
|
|
340
|
-
self.mask,
|
|
341
296
|
fill_value=np.nan,
|
|
342
297
|
)
|
|
343
298
|
|
|
344
|
-
def
|
|
345
|
-
mask_path = experiment_path / "grid_mask.npy"
|
|
346
|
-
if not mask_path.exists():
|
|
347
|
-
mask, _ = read_mask(self.grid_file)
|
|
348
|
-
np.save(mask_path, mask)
|
|
349
|
-
self.mask_file = mask_path
|
|
350
|
-
|
|
351
|
-
@cached_property
|
|
352
|
-
def mask(self) -> Any:
|
|
353
|
-
if self.mask_file is None:
|
|
354
|
-
raise ValueError(
|
|
355
|
-
"In order to get Field.mask, Field.save_experiment_data has"
|
|
356
|
-
" to be called first"
|
|
357
|
-
)
|
|
358
|
-
return np.load(self.mask_file)
|
|
359
|
-
|
|
360
|
-
def load_parameter_graph(self) -> nx.Graph: # type: ignore
|
|
299
|
+
def load_parameter_graph(self) -> nx.Graph[int]:
|
|
361
300
|
parameter_graph = create_flattened_cube_graph(
|
|
362
301
|
px=self.ertbox_params.nx, py=self.ertbox_params.ny, pz=self.ertbox_params.nz
|
|
363
302
|
)
|
|
364
|
-
|
|
303
|
+
new_labels = {
|
|
304
|
+
old_label: new_label
|
|
305
|
+
for new_label, old_label in enumerate(parameter_graph.nodes())
|
|
306
|
+
}
|
|
307
|
+
return nx.relabel_nodes(parameter_graph, new_labels, copy=True)
|
|
365
308
|
|
|
366
309
|
@property
|
|
367
310
|
def nx(self) -> int:
|
|
@@ -375,8 +318,77 @@ class Field(ParameterConfig):
|
|
|
375
318
|
def nz(self) -> int:
|
|
376
319
|
return self.ertbox_params.nz
|
|
377
320
|
|
|
321
|
+
def calc_rho_for_2d_grid_layer(
|
|
322
|
+
self,
|
|
323
|
+
obs_xpos: npt.NDArray[np.float64],
|
|
324
|
+
obs_ypos: npt.NDArray[np.float64],
|
|
325
|
+
obs_main_range: npt.NDArray[np.float64],
|
|
326
|
+
obs_perp_range: npt.NDArray[np.float64],
|
|
327
|
+
obs_anisotropy_angle: npt.NDArray[np.float64],
|
|
328
|
+
right_handed_grid_indexing: bool = True,
|
|
329
|
+
) -> npt.NDArray[np.float64]:
|
|
330
|
+
"""Function to calculate scaling values to be used in the RHO matrix
|
|
331
|
+
for distance-based localization.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
obs_xpos: x-coordinates in global coordinates of observations
|
|
335
|
+
obs_ypos: y-coordinates in global coordinates of observations
|
|
336
|
+
obs_main_range: Size of influence ellipse main principal direction.
|
|
337
|
+
obs_perp_range: Size of influence ellipse second principal direction.
|
|
338
|
+
obs_anisotropy_angle: Rotation angle anticlock wise of main principal
|
|
339
|
+
direction of influence ellipse relative to global coordinate
|
|
340
|
+
system's x-axis.
|
|
341
|
+
right_handed_grid_indexing: When this is True the field parameters
|
|
342
|
+
grid index order counts J-index down from ny-1 to 0.
|
|
343
|
+
If the value is False, the grid index order is to count J index
|
|
344
|
+
from 0 to ny-1. As standard for 3D field parameters,
|
|
345
|
+
the grid index order follows the right_handed grid indexing.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Scaling values (elements of the RHO matrix) as a numpy array
|
|
349
|
+
of shape=(nx,ny,nobservations)
|
|
350
|
+
|
|
351
|
+
"""
|
|
352
|
+
# Can only be used if ertbox coordinate system is defined
|
|
353
|
+
assert self.ertbox_params.xinc is not None, (
|
|
354
|
+
"Parameter for grid resolution must be defined"
|
|
355
|
+
)
|
|
356
|
+
assert self.ertbox_params.yinc is not None, (
|
|
357
|
+
"Parameter for grid resolution must be defined"
|
|
358
|
+
)
|
|
359
|
+
assert self.ertbox_params.origin is not None, (
|
|
360
|
+
"Parameter for grid origin must be defined"
|
|
361
|
+
)
|
|
362
|
+
assert self.ertbox_params.rotation_angle is not None, (
|
|
363
|
+
"Parameter for grid rotation must be defined"
|
|
364
|
+
)
|
|
365
|
+
# Transform positions of observations into local coordinates
|
|
366
|
+
xpos, ypos = transform_positions_to_local_field_coordinates(
|
|
367
|
+
self.ertbox_params.origin,
|
|
368
|
+
self.ertbox_params.rotation_angle,
|
|
369
|
+
obs_xpos,
|
|
370
|
+
obs_ypos,
|
|
371
|
+
)
|
|
372
|
+
# Transform localization ellipse orientation to local coordinates
|
|
373
|
+
ellipse_rotation = transform_local_ellipse_angle_to_local_coords(
|
|
374
|
+
self.ertbox_params.rotation_angle, obs_anisotropy_angle
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
return calc_rho_for_2d_grid_layer(
|
|
378
|
+
self.ertbox_params.nx,
|
|
379
|
+
self.ertbox_params.ny,
|
|
380
|
+
self.ertbox_params.xinc,
|
|
381
|
+
self.ertbox_params.yinc,
|
|
382
|
+
xpos,
|
|
383
|
+
ypos,
|
|
384
|
+
obs_main_range,
|
|
385
|
+
obs_perp_range,
|
|
386
|
+
ellipse_rotation,
|
|
387
|
+
right_handed_grid_indexing=right_handed_grid_indexing,
|
|
388
|
+
)
|
|
389
|
+
|
|
378
390
|
|
|
379
|
-
TRANSFORM_FUNCTIONS = {
|
|
391
|
+
TRANSFORM_FUNCTIONS: Final[dict[str, Callable[[Any], Any]]] = {
|
|
380
392
|
"LN": np.log,
|
|
381
393
|
"LOG": np.log,
|
|
382
394
|
"LN0": lambda v: np.log(v + 0.000001),
|
|
@@ -407,7 +419,7 @@ def field_transform(
|
|
|
407
419
|
) -> npt.NDArray[np.float32] | xr.DataArray:
|
|
408
420
|
if transform_name is None:
|
|
409
421
|
return data
|
|
410
|
-
return TRANSFORM_FUNCTIONS[transform_name](data)
|
|
422
|
+
return TRANSFORM_FUNCTIONS[transform_name](data)
|
|
411
423
|
|
|
412
424
|
|
|
413
425
|
def _field_truncate(data: npt.ArrayLike, min_: float | None, max_: float | None) -> Any:
|
ert/config/forward_model_step.py
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Annotated,
|
|
7
|
+
Any,
|
|
8
|
+
ClassVar,
|
|
9
|
+
Literal,
|
|
10
|
+
NotRequired,
|
|
11
|
+
Self,
|
|
12
|
+
cast,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from pydantic import (
|
|
16
|
+
BaseModel,
|
|
17
|
+
Field,
|
|
18
|
+
field_validator,
|
|
19
|
+
model_serializer,
|
|
20
|
+
model_validator,
|
|
21
|
+
)
|
|
22
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
7
23
|
from typing_extensions import TypedDict, Unpack
|
|
8
24
|
|
|
25
|
+
from ..base_model_context import BaseModelWithContextSupport
|
|
9
26
|
from .parsing import ConfigValidationError, ConfigWarning, SchemaItemType
|
|
10
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from ert.plugins import ErtRuntimePlugins
|
|
30
|
+
|
|
11
31
|
logger = logging.getLogger(__name__)
|
|
12
32
|
|
|
13
33
|
|
|
@@ -72,6 +92,7 @@ class ForwardModelStepOptions(TypedDict, total=False):
|
|
|
72
92
|
max_running_minutes: NotRequired[int]
|
|
73
93
|
environment: NotRequired[dict[str, str]]
|
|
74
94
|
default_mapping: NotRequired[dict[str, str]]
|
|
95
|
+
required_keywords: NotRequired[list[str]]
|
|
75
96
|
|
|
76
97
|
|
|
77
98
|
class ForwardModelStepDocumentation(BaseModel):
|
|
@@ -80,18 +101,21 @@ class ForwardModelStepDocumentation(BaseModel):
|
|
|
80
101
|
source_function_name: str = Field(default="ert")
|
|
81
102
|
description: str = Field(default="No description")
|
|
82
103
|
examples: str = Field(default="No examples")
|
|
83
|
-
category:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
category: Annotated[
|
|
105
|
+
str,
|
|
106
|
+
Field(
|
|
107
|
+
default="Uncategorized",
|
|
108
|
+
examples=[
|
|
109
|
+
"utility.file_system",
|
|
110
|
+
"simulators.reservoir",
|
|
111
|
+
"modelling.reservoir",
|
|
112
|
+
"utility.templating",
|
|
113
|
+
],
|
|
114
|
+
),
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class ForwardModelStep(BaseModelWithContextSupport):
|
|
95
119
|
"""
|
|
96
120
|
Holds information to execute one step of a forward model
|
|
97
121
|
|
|
@@ -202,7 +226,87 @@ class ForwardModelStep(BaseModel):
|
|
|
202
226
|
return None if v == "null" else v
|
|
203
227
|
|
|
204
228
|
|
|
205
|
-
class
|
|
229
|
+
class UserInstalledForwardModelStep(ForwardModelStep):
|
|
230
|
+
"""
|
|
231
|
+
Represents a forward model step installed by a user via the ERT Config
|
|
232
|
+
forward model step format provided via the INSTALL_JOB keyword.
|
|
233
|
+
User-installed forward model steps serialize with their full configuration,
|
|
234
|
+
unlike site-installed steps which only serialize as references.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
type: Literal["user_installed"] = "user_installed"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class _SerializedSiteInstalledForwardModelStep(TypedDict):
|
|
241
|
+
type: Literal["site_installed"]
|
|
242
|
+
name: str
|
|
243
|
+
private_args: dict[str, str]
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class SiteInstalledForwardModelStep(ForwardModelStep):
|
|
247
|
+
"""
|
|
248
|
+
Represents a forward model step installed via external plugins.
|
|
249
|
+
Instances of this class serialize only as references to the plugin by name, and
|
|
250
|
+
the user-provided private_args, allowing them to dynamically update when plugins
|
|
251
|
+
change, rather than being locked to a specific executable at serialization time.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
type: Literal["site_installed"] = "site_installed"
|
|
255
|
+
|
|
256
|
+
@model_serializer(mode="plain")
|
|
257
|
+
def serialize_model(self) -> _SerializedSiteInstalledForwardModelStep:
|
|
258
|
+
return {
|
|
259
|
+
"type": "site_installed",
|
|
260
|
+
"name": self.name,
|
|
261
|
+
"private_args": self.private_args,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@model_validator(mode="before")
|
|
265
|
+
@classmethod
|
|
266
|
+
def deserialize_model(
|
|
267
|
+
cls, values: dict[str, Any], info: ValidationInfo
|
|
268
|
+
) -> dict[str, Any]:
|
|
269
|
+
runtime_plugins = cast("ErtRuntimePlugins", info.context)
|
|
270
|
+
name = values["name"]
|
|
271
|
+
|
|
272
|
+
if runtime_plugins is None:
|
|
273
|
+
if values.get("type") == "site_installed":
|
|
274
|
+
msg = (
|
|
275
|
+
f"Trying to find site-installed forward model step {name} "
|
|
276
|
+
f"without site plugins. This forward model must be loaded "
|
|
277
|
+
f"with ERT site plugins available."
|
|
278
|
+
)
|
|
279
|
+
raise KeyError(msg)
|
|
280
|
+
return values
|
|
281
|
+
|
|
282
|
+
if name not in runtime_plugins.installed_forward_model_steps:
|
|
283
|
+
msg = (
|
|
284
|
+
f"Expected forward model step {name} to be installed "
|
|
285
|
+
f"via plugins, but it was not found. Please check that "
|
|
286
|
+
f"your python environment has it installed."
|
|
287
|
+
)
|
|
288
|
+
raise KeyError(msg)
|
|
289
|
+
site_installed_fm = runtime_plugins.installed_forward_model_steps[name]
|
|
290
|
+
|
|
291
|
+
# Intent: copy the site installed forward model to this instance.
|
|
292
|
+
# bypassing the model_serializer
|
|
293
|
+
site_fm_instance = {
|
|
294
|
+
k: getattr(site_installed_fm, k)
|
|
295
|
+
for k in SiteInstalledForwardModelStep.model_fields
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return site_fm_instance | (
|
|
299
|
+
{"private_args": values["private_args"]} if "private_args" in values else {}
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
SiteOrUserForwardModelStep = Annotated[
|
|
304
|
+
(UserInstalledForwardModelStep | SiteInstalledForwardModelStep),
|
|
305
|
+
Field(discriminator="type"),
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class ForwardModelStepPlugin(SiteInstalledForwardModelStep):
|
|
206
310
|
def __init__(
|
|
207
311
|
self, name: str, command: list[str], **kwargs: Unpack[ForwardModelStepOptions]
|
|
208
312
|
) -> None:
|
|
@@ -221,6 +325,7 @@ class ForwardModelStepPlugin(ForwardModelStep):
|
|
|
221
325
|
max_running_minutes = kwargs.get("max_running_minutes")
|
|
222
326
|
environment = kwargs.get("environment", {}) or {}
|
|
223
327
|
default_mapping = kwargs.get("default_mapping", {}) or {}
|
|
328
|
+
required_keywords = kwargs.get("required_keywords", []) or []
|
|
224
329
|
|
|
225
330
|
super().__init__(
|
|
226
331
|
name=name,
|
|
@@ -235,7 +340,7 @@ class ForwardModelStepPlugin(ForwardModelStep):
|
|
|
235
340
|
max_running_minutes=max_running_minutes,
|
|
236
341
|
min_arg=0,
|
|
237
342
|
max_arg=0,
|
|
238
|
-
required_keywords=
|
|
343
|
+
required_keywords=required_keywords,
|
|
239
344
|
arg_types=[],
|
|
240
345
|
environment=environment,
|
|
241
346
|
default_mapping=default_mapping,
|
ert/config/gen_data_config.py
CHANGED
|
@@ -21,7 +21,6 @@ from .responses_index import responses_index
|
|
|
21
21
|
|
|
22
22
|
class GenDataConfig(ResponseConfig):
|
|
23
23
|
type: Literal["gen_data"] = "gen_data"
|
|
24
|
-
name: str = "gen_data"
|
|
25
24
|
report_steps_list: list[list[int] | None] = Field(default_factory=list)
|
|
26
25
|
has_finalized_keys: bool = True
|
|
27
26
|
|
|
@@ -29,7 +28,7 @@ class GenDataConfig(ResponseConfig):
|
|
|
29
28
|
def metadata(self) -> list[ResponseMetadata]:
|
|
30
29
|
return [
|
|
31
30
|
ResponseMetadata(
|
|
32
|
-
response_type=self.
|
|
31
|
+
response_type=self.type,
|
|
33
32
|
response_key=response_key,
|
|
34
33
|
finalized=self.has_finalized_keys,
|
|
35
34
|
filter_on={"report_step": report_steps}
|
|
@@ -198,28 +197,24 @@ class GenDataConfig(ResponseConfig):
|
|
|
198
197
|
if all(isinstance(err, FileNotFoundError) for err in errors):
|
|
199
198
|
raise FileNotFoundError(
|
|
200
199
|
"Could not find one or more files/directories while reading "
|
|
201
|
-
f"GEN_DATA
|
|
200
|
+
f"GEN_DATA: {','.join([str(err) for err in errors])}"
|
|
202
201
|
)
|
|
203
202
|
else:
|
|
204
203
|
raise InvalidResponseFile(
|
|
205
204
|
"Error reading GEN_DATA "
|
|
206
|
-
f"{self.
|
|
205
|
+
f"{self.type}, errors: {','.join([str(err) for err in errors])}"
|
|
207
206
|
)
|
|
208
207
|
|
|
209
208
|
combined = pl.concat(datasets_per_name)
|
|
210
209
|
return combined
|
|
211
210
|
|
|
212
211
|
def get_args_for_key(self, key: str) -> tuple[str | None, list[int] | None]:
|
|
213
|
-
for i,
|
|
214
|
-
if key ==
|
|
212
|
+
for i, key_ in enumerate(self.keys):
|
|
213
|
+
if key == key_:
|
|
215
214
|
return self.input_files[i], self.report_steps_list[i]
|
|
216
215
|
|
|
217
216
|
return None, None
|
|
218
217
|
|
|
219
|
-
@property
|
|
220
|
-
def response_type(self) -> str:
|
|
221
|
-
return "gen_data"
|
|
222
|
-
|
|
223
218
|
@property
|
|
224
219
|
def primary_key(self) -> list[str]:
|
|
225
220
|
return ["report_step", "index"]
|
ert/config/gen_kw_config.py
CHANGED
|
@@ -15,7 +15,7 @@ from typing_extensions import TypedDict
|
|
|
15
15
|
|
|
16
16
|
from ._str_to_bool import str_to_bool
|
|
17
17
|
from .distribution import DISTRIBUTION_CLASSES, DistributionSettings, get_distribution
|
|
18
|
-
from .parameter_config import ParameterCardinality, ParameterConfig
|
|
18
|
+
from .parameter_config import ParameterCardinality, ParameterConfig
|
|
19
19
|
from .parsing import ConfigValidationError, ConfigWarning
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
@@ -53,6 +53,7 @@ class DataSource(StrEnum):
|
|
|
53
53
|
|
|
54
54
|
class GenKwConfig(ParameterConfig):
|
|
55
55
|
type: Literal["gen_kw"] = "gen_kw"
|
|
56
|
+
dimensionality: Literal[1] = 1
|
|
56
57
|
distribution: DistributionSettings
|
|
57
58
|
forward_init: bool = False
|
|
58
59
|
update: bool = True
|
|
@@ -73,17 +74,6 @@ class GenKwConfig(ParameterConfig):
|
|
|
73
74
|
def cardinality(self) -> ParameterCardinality:
|
|
74
75
|
return ParameterCardinality.multiple_configs_per_ensemble_dataset
|
|
75
76
|
|
|
76
|
-
@property
|
|
77
|
-
def metadata(self) -> list[ParameterMetadata]:
|
|
78
|
-
return [
|
|
79
|
-
ParameterMetadata(
|
|
80
|
-
key=f"{self.group}:{self.name}",
|
|
81
|
-
transformation=self.distribution.name.upper(),
|
|
82
|
-
dimensionality=1,
|
|
83
|
-
userdata={"data_origin": "GEN_KW"},
|
|
84
|
-
)
|
|
85
|
-
]
|
|
86
|
-
|
|
87
77
|
@classmethod
|
|
88
78
|
def templates_from_config(
|
|
89
79
|
cls, gen_kw: list[str | dict[str, str]]
|
|
@@ -121,7 +111,7 @@ class GenKwConfig(ParameterConfig):
|
|
|
121
111
|
gen_kw_key = cast(str, config_list[0])
|
|
122
112
|
|
|
123
113
|
options = cast(dict[str, str], config_list[-1])
|
|
124
|
-
positional_args = cast(list[str], config_list[:-1])
|
|
114
|
+
positional_args = cast(list[str | list[str]], config_list[:-1])
|
|
125
115
|
errors = []
|
|
126
116
|
update_parameter = str_to_bool(options.get("UPDATE", "TRUE"))
|
|
127
117
|
if _get_abs_path(options.get("INIT_FILES")):
|
|
@@ -186,7 +176,7 @@ class GenKwConfig(ParameterConfig):
|
|
|
186
176
|
params[0], params[1], params[2:]
|
|
187
177
|
),
|
|
188
178
|
forward_init=False,
|
|
189
|
-
update=update_parameter,
|
|
179
|
+
update="CONST" not in params and update_parameter,
|
|
190
180
|
)
|
|
191
181
|
for params in distributions_spec
|
|
192
182
|
]
|
|
@@ -217,18 +207,7 @@ class GenKwConfig(ParameterConfig):
|
|
|
217
207
|
real_nr: int,
|
|
218
208
|
ensemble: Ensemble,
|
|
219
209
|
) -> dict[str, dict[str, float | str]]:
|
|
220
|
-
|
|
221
|
-
"realization"
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
assert isinstance(df, pl.DataFrame)
|
|
225
|
-
if not df.width == 1:
|
|
226
|
-
raise ValueError(
|
|
227
|
-
f"GEN_KW {self.group_name}:{self.name} should be a single parameter!"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
data = df.to_dicts()[0]
|
|
231
|
-
return {self.group_name: data}
|
|
210
|
+
raise NotImplementedError
|
|
232
211
|
|
|
233
212
|
def load_parameters(
|
|
234
213
|
self, ensemble: Ensemble, realizations: npt.NDArray[np.int_]
|
|
@@ -259,15 +238,6 @@ class GenKwConfig(ParameterConfig):
|
|
|
259
238
|
def group_name(self) -> str:
|
|
260
239
|
return self.group
|
|
261
240
|
|
|
262
|
-
def copy_parameters(
|
|
263
|
-
self,
|
|
264
|
-
source_ensemble: Ensemble,
|
|
265
|
-
target_ensemble: Ensemble,
|
|
266
|
-
realizations: npt.NDArray[np.int_],
|
|
267
|
-
) -> None:
|
|
268
|
-
df = source_ensemble.load_parameters(self.name, realizations)
|
|
269
|
-
target_ensemble.save_parameters(dataset=df)
|
|
270
|
-
|
|
271
241
|
def get_priors(self) -> list[PriorDict]:
|
|
272
242
|
dist_json = self.distribution.model_dump(exclude={"name"})
|
|
273
243
|
return [
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .everest_response import EverestConstraintsConfig, EverestObjectivesConfig
|
|
2
|
+
from .gen_data_config import GenDataConfig
|
|
3
|
+
from .rft_config import RFTConfig
|
|
4
|
+
from .summary_config import SummaryConfig
|
|
5
|
+
|
|
6
|
+
KnownErtResponseTypes = SummaryConfig | GenDataConfig | RFTConfig
|
|
7
|
+
KNOWN_ERT_RESPONSE_TYPES = (
|
|
8
|
+
SummaryConfig,
|
|
9
|
+
GenDataConfig,
|
|
10
|
+
RFTConfig,
|
|
11
|
+
)
|
|
12
|
+
KnownResponseTypes = (
|
|
13
|
+
KnownErtResponseTypes | EverestConstraintsConfig | EverestObjectivesConfig
|
|
14
|
+
)
|
ert/config/parameter_config.py
CHANGED
|
@@ -5,7 +5,7 @@ from collections.abc import Callable, Iterator
|
|
|
5
5
|
from enum import StrEnum, auto
|
|
6
6
|
from hashlib import sha256
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
9
|
|
|
10
10
|
import networkx as nx
|
|
11
11
|
import numpy as np
|
|
@@ -39,13 +39,6 @@ class ParameterCardinality(StrEnum):
|
|
|
39
39
|
one_config_per_realization_dataset = auto()
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class ParameterMetadata(BaseModel):
|
|
43
|
-
key: str
|
|
44
|
-
transformation: str | None
|
|
45
|
-
dimensionality: Literal[1, 2, 3] = 1
|
|
46
|
-
userdata: dict[str, Any]
|
|
47
|
-
|
|
48
|
-
|
|
49
42
|
class ParameterConfig(BaseModel):
|
|
50
43
|
type: str
|
|
51
44
|
name: str
|
|
@@ -59,14 +52,6 @@ class ParameterConfig(BaseModel):
|
|
|
59
52
|
Returns a list of parameter keys within this parameter group
|
|
60
53
|
"""
|
|
61
54
|
|
|
62
|
-
@property
|
|
63
|
-
@abstractmethod
|
|
64
|
-
def metadata(self) -> list[ParameterMetadata]:
|
|
65
|
-
"""
|
|
66
|
-
Returns metadata describing this parameter
|
|
67
|
-
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
55
|
@abstractmethod
|
|
71
56
|
def __len__(self) -> int:
|
|
72
57
|
"""Number of parameters"""
|
|
@@ -108,23 +93,6 @@ class ParameterConfig(BaseModel):
|
|
|
108
93
|
or polars DataFrame from the numpy data
|
|
109
94
|
"""
|
|
110
95
|
|
|
111
|
-
def copy_parameters(
|
|
112
|
-
self,
|
|
113
|
-
source_ensemble: Ensemble,
|
|
114
|
-
target_ensemble: Ensemble,
|
|
115
|
-
realizations: npt.NDArray[np.int_],
|
|
116
|
-
) -> None:
|
|
117
|
-
"""
|
|
118
|
-
Copy parameters from one ensemble to another.
|
|
119
|
-
If realizations is None, copy all realizations.
|
|
120
|
-
If realizations is given, copy only those realizations.
|
|
121
|
-
"""
|
|
122
|
-
for realization in realizations:
|
|
123
|
-
# Converts to standard python scalar due to mypy
|
|
124
|
-
realization_int = int(realization)
|
|
125
|
-
ds = source_ensemble.load_parameters(self.name, realization_int)
|
|
126
|
-
target_ensemble.save_parameters(ds, self.name, realization_int)
|
|
127
|
-
|
|
128
96
|
@abstractmethod
|
|
129
97
|
def load_parameters(
|
|
130
98
|
self, ensemble: Ensemble, realizations: npt.NDArray[np.int_]
|