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/storage/local_storage.py
CHANGED
|
@@ -5,14 +5,14 @@ import logging
|
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
7
|
import shutil
|
|
8
|
+
import types
|
|
8
9
|
from collections.abc import Generator, MutableSequence
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from functools import cached_property
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from tempfile import NamedTemporaryFile
|
|
13
14
|
from textwrap import dedent
|
|
14
|
-
from
|
|
15
|
-
from typing import Any
|
|
15
|
+
from typing import Any, Self
|
|
16
16
|
from uuid import UUID, uuid4
|
|
17
17
|
|
|
18
18
|
import polars as pl
|
|
@@ -20,6 +20,7 @@ import xarray as xr
|
|
|
20
20
|
from filelock import FileLock, Timeout
|
|
21
21
|
from pydantic import BaseModel, Field
|
|
22
22
|
|
|
23
|
+
import ert.storage
|
|
23
24
|
from ert.config import ErtConfig, ParameterConfig, ResponseConfig
|
|
24
25
|
from ert.shared import __version__
|
|
25
26
|
|
|
@@ -30,7 +31,7 @@ from .realization_storage_state import RealizationStorageState
|
|
|
30
31
|
|
|
31
32
|
logger = logging.getLogger(__name__)
|
|
32
33
|
|
|
33
|
-
_LOCAL_STORAGE_VERSION =
|
|
34
|
+
_LOCAL_STORAGE_VERSION = 21
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
class _Migrations(BaseModel):
|
|
@@ -64,8 +65,7 @@ class LocalStorage(BaseMode):
|
|
|
64
65
|
self,
|
|
65
66
|
path: str | os.PathLike[str],
|
|
66
67
|
mode: Mode,
|
|
67
|
-
|
|
68
|
-
ignore_migration_check: bool = False,
|
|
68
|
+
stage_for_migration: bool = False,
|
|
69
69
|
) -> None:
|
|
70
70
|
"""
|
|
71
71
|
Initializes the LocalStorage instance.
|
|
@@ -76,19 +76,22 @@ class LocalStorage(BaseMode):
|
|
|
76
76
|
The file system path to the storage.
|
|
77
77
|
mode : Mode
|
|
78
78
|
The access mode for the storage (read/write).
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
stage_for_migration : bool
|
|
80
|
+
Whether to avoid reloading storage to allow migration
|
|
81
81
|
"""
|
|
82
82
|
|
|
83
|
-
super().__init__(mode)
|
|
84
83
|
self.path = Path(path).absolute()
|
|
84
|
+
super().__init__(mode)
|
|
85
|
+
|
|
86
|
+
if mode.can_write:
|
|
87
|
+
self._acquire_lock()
|
|
85
88
|
|
|
86
|
-
self._experiments: dict[UUID, LocalExperiment]
|
|
87
|
-
self._ensembles: dict[UUID, LocalEnsemble]
|
|
88
|
-
self._index: _Index
|
|
89
|
+
self._experiments: dict[UUID, LocalExperiment] = {}
|
|
90
|
+
self._ensembles: dict[UUID, LocalEnsemble] = {}
|
|
91
|
+
self._index: _Index = _Index()
|
|
89
92
|
|
|
90
93
|
try:
|
|
91
|
-
version = _storage_version(self.path)
|
|
94
|
+
self.version = _storage_version(self.path)
|
|
92
95
|
except FileNotFoundError as err:
|
|
93
96
|
# No index json, will have a problem if other components of storage exists
|
|
94
97
|
errors = []
|
|
@@ -100,28 +103,45 @@ class LocalStorage(BaseMode):
|
|
|
100
103
|
errors.append(f"ensemble path: {self.path / self.ENSEMBLES_PATH}")
|
|
101
104
|
if errors:
|
|
102
105
|
raise ValueError(f"No index.json, but found: {errors}") from err
|
|
103
|
-
version = _LOCAL_STORAGE_VERSION
|
|
106
|
+
self.version = _LOCAL_STORAGE_VERSION
|
|
104
107
|
|
|
105
|
-
if
|
|
106
|
-
raise RuntimeError(
|
|
107
|
-
f"Cannot open storage '{self.path}': Storage version {version} "
|
|
108
|
-
f"is newer than the current version {_LOCAL_STORAGE_VERSION}, "
|
|
109
|
-
"upgrade ert to continue, or run with a different ENSPATH"
|
|
110
|
-
)
|
|
111
|
-
if self.can_write:
|
|
112
|
-
self._acquire_lock()
|
|
113
|
-
if version < _LOCAL_STORAGE_VERSION and not ignore_migration_check:
|
|
114
|
-
self._migrate(version)
|
|
115
|
-
self._index = self._load_index()
|
|
116
|
-
self._save_index()
|
|
117
|
-
elif version < _LOCAL_STORAGE_VERSION:
|
|
108
|
+
if self.check_migration_needed(Path(self.path)) and not self.can_write:
|
|
118
109
|
raise RuntimeError(
|
|
119
110
|
f"Cannot open storage '{self.path}' in read-only mode: "
|
|
120
|
-
f"Storage version {version} is too old.
|
|
111
|
+
f"Storage version {self.version} is too old. "
|
|
112
|
+
f"Run ert to initiate migration."
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if not stage_for_migration:
|
|
116
|
+
self.reload()
|
|
117
|
+
|
|
118
|
+
if mode.can_write:
|
|
119
|
+
self._save_index()
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def check_migration_needed(storage_dir: Path) -> bool:
|
|
123
|
+
try:
|
|
124
|
+
version = _storage_version(storage_dir)
|
|
125
|
+
except FileNotFoundError:
|
|
126
|
+
version = _LOCAL_STORAGE_VERSION
|
|
127
|
+
|
|
128
|
+
if version > _LOCAL_STORAGE_VERSION:
|
|
129
|
+
raise ert.storage.ErtStorageException(
|
|
130
|
+
f"Cannot open storage '{storage_dir.absolute()}': Storage version "
|
|
131
|
+
f"{version} is newer than the current version {_LOCAL_STORAGE_VERSION}"
|
|
132
|
+
f", upgrade ert to continue, or run with a different ENSPATH"
|
|
121
133
|
)
|
|
122
|
-
self.refresh()
|
|
123
134
|
|
|
124
|
-
|
|
135
|
+
return version < _LOCAL_STORAGE_VERSION
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def perform_migration(path: Path) -> None:
|
|
139
|
+
if LocalStorage.check_migration_needed(path):
|
|
140
|
+
with LocalStorage(path, Mode("w"), True) as storage:
|
|
141
|
+
storage._migrate(storage.version)
|
|
142
|
+
storage.reload()
|
|
143
|
+
|
|
144
|
+
def reload(self) -> None:
|
|
125
145
|
"""
|
|
126
146
|
Reloads the index, experiments, and ensembles from the storage.
|
|
127
147
|
|
|
@@ -257,14 +277,14 @@ class LocalStorage(BaseMode):
|
|
|
257
277
|
def _swap_path(self) -> Path:
|
|
258
278
|
return self.path / self.SWAP_PATH
|
|
259
279
|
|
|
260
|
-
def __enter__(self) ->
|
|
280
|
+
def __enter__(self) -> Self:
|
|
261
281
|
return self
|
|
262
282
|
|
|
263
283
|
def __exit__(
|
|
264
284
|
self,
|
|
265
|
-
exception:
|
|
266
|
-
exception_type:
|
|
267
|
-
traceback: TracebackType,
|
|
285
|
+
exception: type[BaseException] | None,
|
|
286
|
+
exception_type: BaseException | None,
|
|
287
|
+
traceback: types.TracebackType | None,
|
|
268
288
|
) -> None:
|
|
269
289
|
self.close()
|
|
270
290
|
|
|
@@ -283,22 +303,16 @@ class LocalStorage(BaseMode):
|
|
|
283
303
|
def close(self) -> None:
|
|
284
304
|
"""
|
|
285
305
|
Closes the storage, releasing any acquired locks and saving the index.
|
|
286
|
-
|
|
287
306
|
This method should be called to cleanly close the storage, especially
|
|
288
307
|
when it was opened in write mode. Failing to call this method may leave
|
|
289
308
|
a lock file behind, which would interfere with subsequent access to
|
|
290
309
|
the storage.
|
|
291
310
|
"""
|
|
292
|
-
|
|
293
311
|
self._ensembles.clear()
|
|
294
312
|
self._experiments.clear()
|
|
295
313
|
|
|
296
|
-
if not self.can_write:
|
|
297
|
-
return
|
|
298
|
-
|
|
299
|
-
self._save_index()
|
|
300
|
-
|
|
301
314
|
if self.can_write:
|
|
315
|
+
self._save_index()
|
|
302
316
|
self._release_lock()
|
|
303
317
|
|
|
304
318
|
def _release_lock(self) -> None:
|
|
@@ -497,6 +511,12 @@ class LocalStorage(BaseMode):
|
|
|
497
511
|
to13,
|
|
498
512
|
to14,
|
|
499
513
|
to15,
|
|
514
|
+
to16,
|
|
515
|
+
to17,
|
|
516
|
+
to18,
|
|
517
|
+
to19,
|
|
518
|
+
to20,
|
|
519
|
+
to21,
|
|
500
520
|
)
|
|
501
521
|
|
|
502
522
|
try:
|
|
@@ -526,7 +546,7 @@ class LocalStorage(BaseMode):
|
|
|
526
546
|
|
|
527
547
|
self._index = self._load_index()
|
|
528
548
|
|
|
529
|
-
logger.info("
|
|
549
|
+
logger.info("Storage backed up for version less than 5")
|
|
530
550
|
print(self._legacy_storage_migration_message(bkup_path, "14.6.*"))
|
|
531
551
|
return None
|
|
532
552
|
elif version < _LOCAL_STORAGE_VERSION:
|
|
@@ -541,6 +561,12 @@ class LocalStorage(BaseMode):
|
|
|
541
561
|
12: to13,
|
|
542
562
|
13: to14,
|
|
543
563
|
14: to15,
|
|
564
|
+
15: to16,
|
|
565
|
+
16: to17,
|
|
566
|
+
17: to18,
|
|
567
|
+
18: to19,
|
|
568
|
+
19: to20,
|
|
569
|
+
20: to21,
|
|
544
570
|
}
|
|
545
571
|
for from_version in range(version, _LOCAL_STORAGE_VERSION):
|
|
546
572
|
migrations[from_version].migrate(self.path)
|
|
@@ -558,7 +584,7 @@ class LocalStorage(BaseMode):
|
|
|
558
584
|
Get a unique experiment name
|
|
559
585
|
|
|
560
586
|
If an experiment with the given name exists an _0 is appended
|
|
561
|
-
or _n+1 where n is the
|
|
587
|
+
or _n+1 where n is the largest postfix found for the given experiment name
|
|
562
588
|
"""
|
|
563
589
|
if not experiment_name:
|
|
564
590
|
return self.get_unique_experiment_name("default")
|
ert/storage/migration/to11.py
CHANGED
|
@@ -44,7 +44,7 @@ def migrate(path: Path) -> None:
|
|
|
44
44
|
array = ds.isel(realizations=0, drop=True)["values"]
|
|
45
45
|
realization = int(real_dir.name.split("-")[1])
|
|
46
46
|
|
|
47
|
-
def parse_value(value: float |
|
|
47
|
+
def parse_value(value: float | str) -> float | int | str:
|
|
48
48
|
if isinstance(value, float | int):
|
|
49
49
|
return value
|
|
50
50
|
try:
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
info = "Remove mask file from field config"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def migrate_field_param(parameters_json: dict[str, Any]) -> dict[str, Any]:
|
|
9
|
+
new_configs = {}
|
|
10
|
+
for param_config in parameters_json.values():
|
|
11
|
+
if param_config["type"] == "field":
|
|
12
|
+
del param_config["mask_file"]
|
|
13
|
+
|
|
14
|
+
new_configs[param_config["name"]] = param_config
|
|
15
|
+
return new_configs
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def delete_mask_file(experiment: Path) -> None:
|
|
19
|
+
# delete grid mask file if it exists
|
|
20
|
+
grid_mask_file = experiment / "grid_mask.npy"
|
|
21
|
+
if grid_mask_file.exists():
|
|
22
|
+
grid_mask_file.unlink()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def migrate_fields(experiment: Path) -> None:
|
|
26
|
+
with open(experiment / "parameter.json", encoding="utf-8") as fin:
|
|
27
|
+
parameters_json = json.load(fin)
|
|
28
|
+
|
|
29
|
+
new_parameter_configs = migrate_field_param(parameters_json)
|
|
30
|
+
Path(experiment / "parameter.json").write_text(
|
|
31
|
+
json.dumps(new_parameter_configs, indent=2), encoding="utf-8"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def migrate(path: Path) -> None:
|
|
36
|
+
for experiment in path.glob("experiments/*"):
|
|
37
|
+
migrate_fields(experiment)
|
|
38
|
+
delete_mask_file(experiment)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
info = "Migrate realization error type from IntEnum to StrEnum"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def migrate_realization_errors_json_content(
|
|
9
|
+
error_json: dict[str, Any],
|
|
10
|
+
) -> dict[str, Any]:
|
|
11
|
+
int_to_str = {
|
|
12
|
+
1: "undefined",
|
|
13
|
+
2: "parameters_loaded",
|
|
14
|
+
4: "responses_loaded",
|
|
15
|
+
8: "failure_in_current",
|
|
16
|
+
16: "failure_in_parent",
|
|
17
|
+
# To cover cases who ran with storage version 16
|
|
18
|
+
# and StrEnum _RealizationStorageState
|
|
19
|
+
"undefined": "undefined",
|
|
20
|
+
"parameters_loaded": "parameters_loaded",
|
|
21
|
+
"responses_loaded": "responses_loaded",
|
|
22
|
+
"failure_in_current": "failure_in_current",
|
|
23
|
+
"failure_in_parent": "failure_in_parent",
|
|
24
|
+
}
|
|
25
|
+
return error_json | {"type": int_to_str[error_json["type"]]}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def migrate_realization_errors(path: Path) -> None:
|
|
29
|
+
for realization_error in path.glob("ensembles/*/realization-*/error.json"):
|
|
30
|
+
old_error_json_content = json.loads(
|
|
31
|
+
realization_error.read_text(encoding="utf-8")
|
|
32
|
+
)
|
|
33
|
+
realization_error.write_text(
|
|
34
|
+
json.dumps(
|
|
35
|
+
migrate_realization_errors_json_content(old_error_json_content),
|
|
36
|
+
indent=2,
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def migrate(path: Path) -> None:
|
|
42
|
+
migrate_realization_errors(path)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
info = "Add dimensionality attribute to parameters"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def migrate_param(parameters_json: dict[str, Any]) -> dict[str, Any]:
|
|
9
|
+
new_configs = {}
|
|
10
|
+
for param_config in parameters_json.values():
|
|
11
|
+
if param_config["type"] == "surface":
|
|
12
|
+
param_config["dimensionality"] = 2
|
|
13
|
+
elif param_config["type"] == "field":
|
|
14
|
+
param_config["dimensionality"] = 3
|
|
15
|
+
else:
|
|
16
|
+
param_config["dimensionality"] = 1
|
|
17
|
+
|
|
18
|
+
new_configs[param_config["name"]] = param_config
|
|
19
|
+
return new_configs
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def migrate_parameters_for_experiment(experiment: Path) -> None:
|
|
23
|
+
with open(experiment / "parameter.json", encoding="utf-8") as fin:
|
|
24
|
+
parameters_json = json.load(fin)
|
|
25
|
+
|
|
26
|
+
new_parameter_configs = migrate_param(parameters_json)
|
|
27
|
+
Path(experiment / "parameter.json").write_text(
|
|
28
|
+
json.dumps(new_parameter_configs, indent=2), encoding="utf-8"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def migrate(path: Path) -> None:
|
|
33
|
+
for experiment in path.glob("experiments/*"):
|
|
34
|
+
migrate_parameters_for_experiment(experiment)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
info = "Remove redundant .name attribute from responses."
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def config_without_name_attr(config: dict[str, Any]) -> dict[str, Any]:
|
|
9
|
+
new_json = {**config}
|
|
10
|
+
new_json.pop("name", None)
|
|
11
|
+
|
|
12
|
+
return new_json
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def migrate(path: Path) -> None:
|
|
16
|
+
for response_json_path in path.glob("experiments/*/responses.json"):
|
|
17
|
+
old_json = json.loads((response_json_path).read_text(encoding="utf-8"))
|
|
18
|
+
new_json = {
|
|
19
|
+
response_type: config_without_name_attr(config)
|
|
20
|
+
for response_type, config in old_json.items()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
response_json_path.write_text(json.dumps(new_json, indent=2), encoding="utf-8")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
info = "Remove refcase from summary response configs"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def config_without_refcase(summary_config: dict[str, Any]) -> dict[str, Any]:
|
|
9
|
+
new_json = {**summary_config}
|
|
10
|
+
new_json.pop("refcase", None)
|
|
11
|
+
|
|
12
|
+
return new_json
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def migrate(path: Path) -> None:
|
|
16
|
+
for response_json_path in path.glob("experiments/*/responses.json"):
|
|
17
|
+
old_json = json.loads((response_json_path).read_text(encoding="utf-8"))
|
|
18
|
+
new_json = {
|
|
19
|
+
response_type: config_without_refcase(response_config)
|
|
20
|
+
if response_config["type"] == "summary"
|
|
21
|
+
else response_config
|
|
22
|
+
for response_type, response_config in old_json.items()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
response_json_path.write_text(json.dumps(new_json, indent=2), encoding="utf-8")
|
ert/storage/migration/to8.py
CHANGED
|
@@ -138,14 +138,14 @@ def _migrate_observations_to_grouped_parquet(path: Path) -> None:
|
|
|
138
138
|
|
|
139
139
|
for response_type in ["gen_data", "summary"]:
|
|
140
140
|
infos = [
|
|
141
|
-
|
|
141
|
+
info_ for info_ in obs_ds_infos if info_.response_type == response_type
|
|
142
142
|
]
|
|
143
143
|
if len(infos) > 0:
|
|
144
|
-
concatd_df = pl.concat([
|
|
144
|
+
concatd_df = pl.concat([info_.polars_df for info_ in infos])
|
|
145
145
|
concatd_df.write_parquet(experiment / "observations" / response_type)
|
|
146
146
|
|
|
147
|
-
for
|
|
148
|
-
os.remove(
|
|
147
|
+
for info_ in infos:
|
|
148
|
+
os.remove(info_.original_ds_path)
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
def migrate(path: Path) -> None:
|
ert/substitutions.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import re
|
|
5
5
|
from collections import UserDict
|
|
6
6
|
from collections.abc import Mapping
|
|
7
|
+
from typing import Self
|
|
7
8
|
|
|
8
9
|
logger = logging.getLogger(__name__)
|
|
9
10
|
_PATTERN = re.compile(r"<[^<>]+>")
|
|
@@ -25,44 +26,27 @@ class Substitutions(UserDict[str, str]):
|
|
|
25
26
|
"""
|
|
26
27
|
return _substitute(self, to_substitute, context, max_iterations, warn_max_iter)
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
def substitute_parameters(
|
|
30
|
-
to_substitute: str, parameter_values: Mapping[str, Mapping[str, str | float]]
|
|
31
|
-
) -> str:
|
|
32
|
-
"""Applies the substitution '<param_name>' to parameter value
|
|
33
|
-
Args:
|
|
34
|
-
parameter_values: Mapping from parameter name to parameter value
|
|
35
|
-
to_substitute: string to substitute magic strings in
|
|
36
|
-
Returns:
|
|
37
|
-
substituted string
|
|
38
|
-
"""
|
|
39
|
-
for values in parameter_values.values():
|
|
40
|
-
for param_name, value in values.items():
|
|
41
|
-
if isinstance(value, (int, float)):
|
|
42
|
-
formatted_value = f"{value:.6g}"
|
|
43
|
-
else:
|
|
44
|
-
formatted_value = str(value)
|
|
45
|
-
to_substitute = to_substitute.replace(
|
|
46
|
-
f"<{param_name}>", formatted_value
|
|
47
|
-
)
|
|
48
|
-
return to_substitute
|
|
49
|
-
|
|
50
|
-
def substitute_real_iter(
|
|
51
|
-
self, to_substitute: str, realization: int, iteration: int
|
|
52
|
-
) -> str:
|
|
29
|
+
def real_iter_substituter(self, realization: int, iteration: int) -> Self:
|
|
53
30
|
extra_data = {
|
|
54
31
|
"<IENS>": str(realization),
|
|
55
32
|
"<ITER>": str(iteration),
|
|
56
33
|
}
|
|
57
34
|
|
|
58
|
-
model_id_key = f"<
|
|
35
|
+
model_id_key = f"<REALIZATION_ID_{realization}_{iteration}>"
|
|
59
36
|
if model_id_key in self:
|
|
60
|
-
extra_data["<
|
|
37
|
+
extra_data["<REALIZATION_ID>"] = self[model_id_key]
|
|
61
38
|
sim_id_key = f"<SIM_DIR_{realization}_{iteration}>"
|
|
62
39
|
if sim_id_key in self:
|
|
63
40
|
extra_data["<SIM_DIR>"] = self[sim_id_key]
|
|
64
41
|
|
|
65
|
-
return
|
|
42
|
+
return type(self)({**self, **extra_data})
|
|
43
|
+
|
|
44
|
+
def substitute_real_iter(
|
|
45
|
+
self, to_substitute: str, realization: int, iteration: int
|
|
46
|
+
) -> str:
|
|
47
|
+
return self.real_iter_substituter(realization, iteration).substitute(
|
|
48
|
+
to_substitute
|
|
49
|
+
)
|
|
66
50
|
|
|
67
51
|
def _concise_representation(self) -> str:
|
|
68
52
|
return (
|
ert/validation/active_range.py
CHANGED
|
@@ -47,19 +47,19 @@ class ActiveRange:
|
|
|
47
47
|
raise ValueError(
|
|
48
48
|
f"Only digits, commas, dashes and spaces are allowed, got {rangestring}"
|
|
49
49
|
)
|
|
50
|
-
for
|
|
51
|
-
if "-" in
|
|
52
|
-
if len(
|
|
53
|
-
raise ValueError(f"Invalid range specified, got {
|
|
54
|
-
realization_bounds =
|
|
50
|
+
for range_ in rangestring.split(","):
|
|
51
|
+
if "-" in range_:
|
|
52
|
+
if len(range_.split("-")) != 2:
|
|
53
|
+
raise ValueError(f"Invalid range specified, got {range_}")
|
|
54
|
+
realization_bounds = range_.split("-")
|
|
55
55
|
start = int(realization_bounds[0])
|
|
56
56
|
end = int(realization_bounds[1])
|
|
57
57
|
if end < start:
|
|
58
58
|
raise ValueError(
|
|
59
|
-
f"Invalid direction in range specified, got {
|
|
59
|
+
f"Invalid direction in range specified, got {range_}"
|
|
60
60
|
)
|
|
61
61
|
else:
|
|
62
|
-
int(
|
|
62
|
+
int(range_)
|
|
63
63
|
return rangestring
|
|
64
64
|
|
|
65
65
|
@classmethod
|
ert/validation/rangestring.py
CHANGED
|
@@ -66,11 +66,11 @@ def rangestring_to_mask(rangestring: str, length: int) -> list[bool]:
|
|
|
66
66
|
# An empty string means no active indecies. Note that an
|
|
67
67
|
# IndexRange-typed instance being None means the opposite
|
|
68
68
|
return mask
|
|
69
|
-
for
|
|
70
|
-
if "-" in
|
|
71
|
-
if len(
|
|
72
|
-
raise ValueError(f"Wrong range syntax {
|
|
73
|
-
start, end = map(int,
|
|
69
|
+
for range_ in rangestring.split(","):
|
|
70
|
+
if "-" in range_:
|
|
71
|
+
if len(range_.strip().split("-")) != 2:
|
|
72
|
+
raise ValueError(f"Wrong range syntax {range_}")
|
|
73
|
+
start, end = map(int, range_.strip().split("-"))
|
|
74
74
|
if end < start:
|
|
75
75
|
raise ValueError(f"Range {start}-{end} has invalid direction")
|
|
76
76
|
if end + 1 > length:
|
|
@@ -78,12 +78,12 @@ def rangestring_to_mask(rangestring: str, length: int) -> list[bool]:
|
|
|
78
78
|
f"Range endpoint {end} is beyond the mask length {length}"
|
|
79
79
|
)
|
|
80
80
|
mask[start : end + 1] = [True] * (end + 1 - start)
|
|
81
|
-
elif
|
|
82
|
-
if int(
|
|
81
|
+
elif range_:
|
|
82
|
+
if int(range_) + 1 > length:
|
|
83
83
|
raise ValueError(
|
|
84
|
-
f"Realization index {
|
|
84
|
+
f"Realization index {range_} is beyond the mask length {length}"
|
|
85
85
|
)
|
|
86
|
-
mask[int(
|
|
86
|
+
mask[int(range_)] = True
|
|
87
87
|
return mask
|
|
88
88
|
|
|
89
89
|
|
|
@@ -102,14 +102,14 @@ def rangestring_to_list(rangestring: str) -> list[int]:
|
|
|
102
102
|
result: set[int] = set()
|
|
103
103
|
if not rangestring:
|
|
104
104
|
return []
|
|
105
|
-
for
|
|
106
|
-
if "-" in
|
|
107
|
-
if len(
|
|
108
|
-
raise ValueError(f"Wrong range syntax {
|
|
109
|
-
start, end = map(int,
|
|
105
|
+
for range_ in rangestring.split(","):
|
|
106
|
+
if "-" in range_:
|
|
107
|
+
if len(range_.strip().split("-")) != 2:
|
|
108
|
+
raise ValueError(f"Wrong range syntax {range_}")
|
|
109
|
+
start, end = map(int, range_.strip().split("-"))
|
|
110
110
|
if end < start:
|
|
111
111
|
raise ValueError(f"Range {start}-{end} has invalid direction")
|
|
112
112
|
result.update(range(start, end + 1))
|
|
113
|
-
elif
|
|
114
|
-
result.add(int(
|
|
113
|
+
elif range_:
|
|
114
|
+
result.add(int(range_))
|
|
115
115
|
return list(result)
|
ert/workflow_runner.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import types
|
|
4
5
|
from concurrent import futures
|
|
5
6
|
from concurrent.futures import Future
|
|
6
7
|
from typing import Any, Self
|
|
@@ -127,7 +128,7 @@ class WorkflowRunner:
|
|
|
127
128
|
self,
|
|
128
129
|
exc_type: type[BaseException] | None,
|
|
129
130
|
exc_value: BaseException | None,
|
|
130
|
-
traceback:
|
|
131
|
+
traceback: types.TracebackType | None,
|
|
131
132
|
) -> None:
|
|
132
133
|
self.wait()
|
|
133
134
|
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ert
|
|
3
|
-
Version:
|
|
3
|
+
Version: 19.0.0rc2
|
|
4
4
|
Summary: Ensemble based Reservoir Tool (ERT)
|
|
5
5
|
Author-email: Equinor ASA <fg_sib-scout@equinor.com>
|
|
6
|
-
License: GPL-3.0
|
|
6
|
+
License-Expression: GPL-3.0-only
|
|
7
7
|
Project-URL: Repository, https://github.com/equinor/ert
|
|
8
8
|
Platform: all
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Environment :: Other Environment
|
|
11
11
|
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
13
12
|
Classifier: Natural Language :: English
|
|
14
13
|
Classifier: Programming Language :: Python
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -21,6 +20,7 @@ Requires-Python: <3.14,>=3.11
|
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
License-File: COPYING
|
|
23
22
|
Requires-Dist: aiohttp
|
|
23
|
+
Requires-Dist: anyio
|
|
24
24
|
Requires-Dist: colorama
|
|
25
25
|
Requires-Dist: cryptography
|
|
26
26
|
Requires-Dist: decorator
|
|
@@ -52,15 +52,15 @@ Requires-Dist: progressbar2
|
|
|
52
52
|
Requires-Dist: psutil
|
|
53
53
|
Requires-Dist: pyarrow
|
|
54
54
|
Requires-Dist: pydantic>2
|
|
55
|
-
Requires-Dist: pyqt6
|
|
55
|
+
Requires-Dist: pyqt6<6.10.0
|
|
56
56
|
Requires-Dist: python-dateutil
|
|
57
57
|
Requires-Dist: python-multipart
|
|
58
58
|
Requires-Dist: pyyaml
|
|
59
59
|
Requires-Dist: pyzmq
|
|
60
60
|
Requires-Dist: requests
|
|
61
61
|
Requires-Dist: resfo>=5.0.0
|
|
62
|
-
Requires-Dist: ropt-dakota<0.
|
|
63
|
-
Requires-Dist: ropt[pandas]<0.
|
|
62
|
+
Requires-Dist: ropt-dakota<0.26,>=0.25
|
|
63
|
+
Requires-Dist: ropt[pandas]<0.26,>=0.25
|
|
64
64
|
Requires-Dist: ruamel.yaml
|
|
65
65
|
Requires-Dist: scipy>=1.10.1
|
|
66
66
|
Requires-Dist: seaborn
|
|
@@ -73,7 +73,7 @@ Requires-Dist: uvicorn>=0.17.0
|
|
|
73
73
|
Requires-Dist: websockets
|
|
74
74
|
Requires-Dist: xarray
|
|
75
75
|
Requires-Dist: xtgeo>=3.3.0
|
|
76
|
-
Requires-Dist: resfo-utilities>=0.
|
|
76
|
+
Requires-Dist: resfo-utilities>=0.5.0
|
|
77
77
|
Provides-Extra: dev
|
|
78
78
|
Requires-Dist: furo; extra == "dev"
|
|
79
79
|
Requires-Dist: hypothesis!=6.102.0,!=6.112.3,>=6.85; extra == "dev"
|
|
@@ -94,6 +94,7 @@ Requires-Dist: pytest-rerunfailures!=16.0; extra == "dev"
|
|
|
94
94
|
Requires-Dist: pytest-snapshot; extra == "dev"
|
|
95
95
|
Requires-Dist: pytest-timeout; extra == "dev"
|
|
96
96
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
97
|
+
Requires-Dist: pytest-durations; extra == "dev"
|
|
97
98
|
Requires-Dist: pytest>6; extra == "dev"
|
|
98
99
|
Requires-Dist: resdata; extra == "dev"
|
|
99
100
|
Requires-Dist: rust-just; extra == "dev"
|
|
@@ -105,7 +106,7 @@ Requires-Dist: sphinx-copybutton; extra == "dev"
|
|
|
105
106
|
Requires-Dist: sphinxcontrib.datatemplates; extra == "dev"
|
|
106
107
|
Requires-Dist: json-schema-for-humans; extra == "dev"
|
|
107
108
|
Requires-Dist: xlsxwriter>=3.2.3; extra == "dev"
|
|
108
|
-
Requires-Dist: resfo-utilities[testing]>=0.
|
|
109
|
+
Requires-Dist: resfo-utilities[testing]>=0.5.0; extra == "dev"
|
|
109
110
|
Provides-Extra: style
|
|
110
111
|
Requires-Dist: pre-commit; extra == "style"
|
|
111
112
|
Provides-Extra: types
|