ert 19.0.1__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.
Files changed (86) hide show
  1. ert/__main__.py +94 -63
  2. ert/analysis/_es_update.py +11 -14
  3. ert/cli/main.py +1 -0
  4. ert/config/__init__.py +3 -2
  5. ert/config/_create_observation_dataframes.py +51 -375
  6. ert/config/_observations.py +483 -200
  7. ert/config/_read_summary.py +4 -5
  8. ert/config/ert_config.py +59 -67
  9. ert/config/everest_control.py +40 -39
  10. ert/config/everest_response.py +1 -13
  11. ert/config/field.py +0 -72
  12. ert/config/forward_model_step.py +17 -1
  13. ert/config/gen_data_config.py +14 -17
  14. ert/config/observation_config_migrations.py +821 -0
  15. ert/config/parameter_config.py +18 -28
  16. ert/config/parsing/__init__.py +0 -1
  17. ert/config/parsing/_parse_zonemap.py +45 -0
  18. ert/config/parsing/config_keywords.py +1 -0
  19. ert/config/parsing/config_schema.py +2 -0
  20. ert/config/parsing/observations_parser.py +2 -0
  21. ert/config/response_config.py +5 -23
  22. ert/config/rft_config.py +44 -19
  23. ert/config/summary_config.py +1 -13
  24. ert/config/surface_config.py +0 -57
  25. ert/dark_storage/compute/misfits.py +0 -42
  26. ert/dark_storage/endpoints/__init__.py +0 -2
  27. ert/dark_storage/endpoints/experiment_server.py +5 -3
  28. ert/dark_storage/endpoints/experiments.py +2 -5
  29. ert/dark_storage/json_schema/experiment.py +1 -2
  30. ert/ensemble_evaluator/config.py +2 -1
  31. ert/field_utils/__init__.py +0 -2
  32. ert/field_utils/field_utils.py +1 -117
  33. ert/gui/ertwidgets/listeditbox.py +9 -1
  34. ert/gui/ertwidgets/models/ertsummary.py +20 -6
  35. ert/gui/ertwidgets/pathchooser.py +9 -1
  36. ert/gui/ertwidgets/stringbox.py +11 -3
  37. ert/gui/ertwidgets/textbox.py +10 -3
  38. ert/gui/ertwidgets/validationsupport.py +19 -1
  39. ert/gui/main_window.py +11 -6
  40. ert/gui/simulation/experiment_panel.py +10 -3
  41. ert/gui/simulation/run_dialog.py +11 -1
  42. ert/gui/tools/manage_experiments/export_dialog.py +4 -0
  43. ert/gui/tools/manage_experiments/manage_experiments_panel.py +1 -0
  44. ert/gui/tools/manage_experiments/storage_info_widget.py +1 -1
  45. ert/gui/tools/manage_experiments/storage_widget.py +18 -3
  46. ert/gui/tools/plot/data_type_proxy_model.py +1 -1
  47. ert/gui/tools/plot/plot_api.py +35 -27
  48. ert/gui/tools/plot/plot_widget.py +5 -0
  49. ert/gui/tools/plot/plot_window.py +4 -7
  50. ert/plugins/plugin_manager.py +4 -0
  51. ert/run_models/ensemble_experiment.py +1 -3
  52. ert/run_models/ensemble_smoother.py +1 -3
  53. ert/run_models/everest_run_model.py +12 -13
  54. ert/run_models/initial_ensemble_run_model.py +19 -22
  55. ert/run_models/model_factory.py +7 -7
  56. ert/run_models/multiple_data_assimilation.py +1 -3
  57. ert/sample_prior.py +12 -14
  58. ert/services/__init__.py +7 -3
  59. ert/services/_storage_main.py +59 -22
  60. ert/services/ert_server.py +186 -24
  61. ert/shared/net_utils.py +43 -18
  62. ert/shared/version.py +3 -3
  63. ert/storage/local_ensemble.py +46 -115
  64. ert/storage/local_experiment.py +0 -16
  65. ert/utils/__init__.py +20 -0
  66. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/METADATA +4 -51
  67. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/RECORD +79 -84
  68. everest/bin/everest_script.py +5 -5
  69. everest/bin/kill_script.py +2 -2
  70. everest/bin/monitor_script.py +2 -2
  71. everest/bin/utils.py +4 -4
  72. everest/detached/everserver.py +6 -6
  73. everest/gui/everest_client.py +0 -6
  74. everest/gui/main_window.py +2 -2
  75. everest/util/__init__.py +1 -19
  76. ert/dark_storage/compute/__init__.py +0 -0
  77. ert/dark_storage/endpoints/compute/__init__.py +0 -0
  78. ert/dark_storage/endpoints/compute/misfits.py +0 -95
  79. ert/services/_base_service.py +0 -387
  80. ert/services/webviz_ert_service.py +0 -20
  81. ert/shared/storage/command.py +0 -38
  82. ert/shared/storage/extraction.py +0 -42
  83. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/WHEEL +0 -0
  84. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/entry_points.txt +0 -0
  85. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/licenses/COPYING +0 -0
  86. {ert-19.0.1.dist-info → ert-20.0.0b0.dist-info}/top_level.txt +0 -0
@@ -15,15 +15,18 @@ from typing import TYPE_CHECKING
15
15
  from uuid import UUID
16
16
 
17
17
  import numpy as np
18
- import pandas as pd
19
18
  import polars as pl
20
19
  import resfo
21
20
  import xarray as xr
22
21
  from pydantic import BaseModel
23
22
  from typing_extensions import TypedDict
24
23
 
25
- from ert.config import ParameterCardinality, ParameterConfig, SummaryConfig
26
- from ert.config.response_config import InvalidResponseFile
24
+ from ert.config import (
25
+ InvalidResponseFile,
26
+ ParameterCardinality,
27
+ ParameterConfig,
28
+ SummaryConfig,
29
+ )
27
30
  from ert.substitutions import substitute_runpath_name
28
31
 
29
32
  from .load_status import LoadResult
@@ -570,30 +573,51 @@ class LocalEnsemble(BaseMode):
570
573
  ) -> pl.DataFrame:
571
574
  if keys is None:
572
575
  keys = self.experiment.parameter_keys
573
- elif set(keys) - set(self.experiment.parameter_keys):
574
- missing = set(keys) - set(self.experiment.parameter_keys)
575
- raise KeyError(f"Parameters not registered to the experiment: {missing}")
576
576
 
577
577
  df_lazy = self._load_parameters_lazy(SCALAR_FILENAME)
578
- df_lazy = df_lazy.select(["realization", *keys])
578
+ names = df_lazy.collect_schema().names()
579
+ matches = [key for key in keys if any(key in item for item in names)]
580
+ if len(matches) != len(keys):
581
+ missing = set(keys) - set(matches)
582
+ raise KeyError(f"Parameters not registered to the experiment: {missing}")
583
+
584
+ parameter_keys = [
585
+ key
586
+ for e in keys
587
+ for key in self.experiment.parameter_configuration[e].parameter_keys
588
+ ]
589
+ df_lazy_filtered = df_lazy.select(["realization", *parameter_keys])
590
+
579
591
  if realizations is not None:
580
592
  if isinstance(realizations, int):
581
593
  realizations = np.array([realizations])
582
- df_lazy = df_lazy.filter(pl.col("realization").is_in(realizations))
583
- df = df_lazy.collect(engine="streaming")
594
+ df_lazy_filtered = df_lazy_filtered.filter(
595
+ pl.col("realization").is_in(realizations)
596
+ )
597
+ df = df_lazy_filtered.collect(engine="streaming")
584
598
  if df.is_empty():
585
599
  raise IndexError(
586
600
  f"No matching realizations {realizations} found for {keys}"
587
601
  )
588
602
 
589
603
  if transformed:
604
+ tmp_configuration: dict[str, ParameterConfig] = {}
605
+ for key in keys:
606
+ for col in df.columns:
607
+ if col == "realization":
608
+ continue
609
+ if col.startswith(key):
610
+ tmp_configuration[col] = (
611
+ self.experiment.parameter_configuration[key]
612
+ )
613
+
590
614
  df = df.with_columns(
591
615
  [
592
616
  pl.col(col)
593
617
  .map_elements(
594
- self.experiment.parameter_configuration[col].transform_data(),
595
- return_dtype=df[col].dtype,
618
+ tmp_configuration[col].transform_data(),
596
619
  )
620
+ .cast(df[col].dtype)
597
621
  .alias(col)
598
622
  for col in df.columns
599
623
  if col != "realization"
@@ -618,13 +642,11 @@ class LocalEnsemble(BaseMode):
618
642
  for p in self.experiment.parameter_configuration.values()
619
643
  if group in {p.name, p.group_name}
620
644
  ]
621
-
622
645
  if not cfgs:
623
646
  raise KeyError(f"{group} is not registered to the experiment.")
624
647
 
625
648
  # if group refers to a group name, we expect the same cardinality
626
649
  cardinality = next(cfg.cardinality for cfg in cfgs)
627
-
628
650
  if cardinality == ParameterCardinality.multiple_configs_per_ensemble_dataset:
629
651
  return self.load_scalar_keys(
630
652
  [cfg.name for cfg in cfgs], realizations, transformed
@@ -741,20 +763,21 @@ class LocalEnsemble(BaseMode):
741
763
  @staticmethod
742
764
  def sample_parameter(
743
765
  parameter: ParameterConfig,
744
- real_nr: int,
766
+ active_realizations: list[int],
745
767
  random_seed: int,
768
+ num_realizations: int,
746
769
  ) -> pl.DataFrame:
747
- parameter_value = parameter.sample_value(
748
- str(random_seed),
749
- real_nr,
770
+ parameter_values = parameter.sample_values(
771
+ str(random_seed), active_realizations, num_realizations=num_realizations
750
772
  )
751
773
 
752
- parameter_dict = {parameter.name: parameter_value[0]}
753
- parameter_dict["realization"] = real_nr
754
- return pl.DataFrame(
755
- parameter_dict,
756
- schema={parameter.name: pl.Float64, "realization": pl.Int64},
774
+ parameters = pl.DataFrame(
775
+ {parameter.name: parameter_values},
776
+ schema={parameter.name: pl.Float64},
757
777
  )
778
+ realizations_series = pl.Series("realization", list(active_realizations))
779
+
780
+ return parameters.with_columns(realizations_series)
758
781
 
759
782
  def load_responses(self, key: str, realizations: tuple[int, ...]) -> pl.DataFrame:
760
783
  """Load responses for key and realizations into xarray Dataset.
@@ -1057,7 +1080,7 @@ class LocalEnsemble(BaseMode):
1057
1080
  pl.col(col).is_in(observed_values.implode())
1058
1081
  )
1059
1082
 
1060
- pivoted = responses.collect(engine="streaming").pivot( # noqa: PD010
1083
+ pivoted = responses.collect(engine="streaming").pivot(
1061
1084
  on="realization",
1062
1085
  index=["response_key", *response_cls.primary_key],
1063
1086
  values="values",
@@ -1190,98 +1213,6 @@ class LocalEnsemble(BaseMode):
1190
1213
  self._path / "index.json", self._index.model_dump_json().encode("utf-8")
1191
1214
  )
1192
1215
 
1193
- @property
1194
- def all_parameters_and_gen_data(self) -> pl.DataFrame | None:
1195
- """
1196
- Only for Everest wrt objectives/constraints,
1197
- disregards summary data and primary key values
1198
- """
1199
- param_dfs = []
1200
- for param_group in self.experiment.parameter_configuration:
1201
- params_pd = self.load_parameters(param_group)["values"].to_pandas()
1202
-
1203
- assert isinstance(params_pd, pd.DataFrame)
1204
- params_pd = params_pd.reset_index()
1205
- param_df = pl.from_pandas(params_pd)
1206
-
1207
- param_columns = [c for c in param_df.columns if c != "realizations"]
1208
- param_df = param_df.rename(
1209
- {
1210
- **{
1211
- c: param_group + "." + c.replace("\0", ".")
1212
- for c in param_columns
1213
- },
1214
- "realizations": "realization",
1215
- }
1216
- )
1217
- param_df = param_df.cast(
1218
- {
1219
- "realization": pl.UInt16,
1220
- **{c: pl.Float64 for c in param_df.columns if c != "realization"},
1221
- }
1222
- )
1223
- param_dfs.append(param_df)
1224
-
1225
- responses = self.load_responses(
1226
- "gen_data", tuple(self.get_realization_list_with_responses())
1227
- )
1228
-
1229
- if responses is None:
1230
- return pl.concat(param_dfs)
1231
-
1232
- params_wide = pl.concat(
1233
- [
1234
- (
1235
- pdf.sort("realization").drop("realization")
1236
- if i > 0
1237
- else pdf.sort("realization")
1238
- )
1239
- for i, pdf in enumerate(param_dfs)
1240
- ],
1241
- how="horizontal",
1242
- )
1243
-
1244
- responses_wide = responses["realization", "response_key", "values"].pivot( # noqa: PD010
1245
- on="response_key", values="values"
1246
- )
1247
-
1248
- # If responses are missing for some realizations, this _left_ join will
1249
- # put null (polars) which maps to nan when doing .to_numpy() into the
1250
- # response columns for those realizations
1251
- params_and_responses = params_wide.join(
1252
- responses_wide, on="realization", how="left"
1253
- ).with_columns(pl.lit(self.iteration).alias("batch"))
1254
-
1255
- assert self.everest_realization_info is not None
1256
-
1257
- model_realization_mapping = {
1258
- k: v["model_realization"] for k, v in self.everest_realization_info.items()
1259
- }
1260
- perturbation_mapping = {
1261
- k: v["perturbation"] for k, v in self.everest_realization_info.items()
1262
- }
1263
-
1264
- params_and_responses = params_and_responses.with_columns(
1265
- pl.col("realization")
1266
- .replace(model_realization_mapping)
1267
- .alias("model_realization"),
1268
- pl.col("realization")
1269
- .cast(pl.Int32)
1270
- .replace(perturbation_mapping)
1271
- .alias("perturbation"),
1272
- )
1273
-
1274
- column_order = [
1275
- "batch",
1276
- "model_realization",
1277
- "perturbation",
1278
- "realization",
1279
- *[c for c in responses_wide.columns if c != "realization"],
1280
- *[c for c in params_wide.columns if c != "realization"],
1281
- ]
1282
-
1283
- return params_and_responses[column_order]
1284
-
1285
1216
 
1286
1217
  async def _read_parameters(
1287
1218
  run_path: str,
@@ -508,19 +508,3 @@ class LocalExperiment(BaseMode):
508
508
 
509
509
  if self.response_type_to_response_keys is not None:
510
510
  del self.response_type_to_response_keys
511
-
512
- @property
513
- def all_parameters_and_gen_data(self) -> pl.DataFrame | None:
514
- if not self.ensembles:
515
- return None
516
-
517
- ensemble_dfs = [
518
- e.all_parameters_and_gen_data
519
- for e in self.ensembles
520
- if e.all_parameters_and_gen_data is not None
521
- ]
522
-
523
- if not ensemble_dfs:
524
- return None
525
-
526
- return pl.concat(ensemble_dfs)
ert/utils/__init__.py CHANGED
@@ -1,9 +1,13 @@
1
1
  import logging
2
2
  import time
3
3
  from collections.abc import Callable
4
+ from datetime import UTC, datetime
4
5
  from functools import wraps
6
+ from pathlib import Path
5
7
  from typing import ParamSpec, TypeVar
6
8
 
9
+ from _ert.utils import file_safe_timestamp
10
+
7
11
  P = ParamSpec("P")
8
12
  R = TypeVar("R")
9
13
 
@@ -30,3 +34,19 @@ def log_duration(
30
34
  return wrapper
31
35
 
32
36
  return decorator
37
+
38
+
39
+ def makedirs_if_needed(path: Path, roll_if_exists: bool = False) -> None:
40
+ if path.is_dir():
41
+ if not roll_if_exists:
42
+ return
43
+ _roll_dir(path) # exists and should be rolled
44
+ path.mkdir(parents=True, exist_ok=False)
45
+
46
+
47
+ def _roll_dir(old_name: Path) -> None:
48
+ old_name = old_name.resolve()
49
+ timestamp = file_safe_timestamp(datetime.now(UTC).isoformat())
50
+ new_name = f"{old_name}__{timestamp}"
51
+ old_name.rename(new_name)
52
+ logging.getLogger().info(f"renamed {old_name} to {new_name}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ert
3
- Version: 19.0.1
3
+ Version: 20.0.0b0
4
4
  Summary: Ensemble based Reservoir Tool (ERT)
5
5
  Author-email: Equinor ASA <fg_sib-scout@equinor.com>
6
6
  License-Expression: GPL-3.0-only
@@ -45,9 +45,9 @@ Requires-Dist: opentelemetry-instrumentation-threading
45
45
  Requires-Dist: opentelemetry-sdk
46
46
  Requires-Dist: orjson
47
47
  Requires-Dist: packaging
48
- Requires-Dist: pandas
48
+ Requires-Dist: pandas<3
49
49
  Requires-Dist: pluggy>=1.3.0
50
- Requires-Dist: polars<1.35,>=1.32.3
50
+ Requires-Dist: polars!=1.35,>=1.32.3
51
51
  Requires-Dist: progressbar2
52
52
  Requires-Dist: psutil
53
53
  Requires-Dist: pyarrow
@@ -74,53 +74,6 @@ Requires-Dist: websockets
74
74
  Requires-Dist: xarray
75
75
  Requires-Dist: xtgeo>=3.3.0
76
76
  Requires-Dist: resfo-utilities>=0.5.0
77
- Provides-Extra: dev
78
- Requires-Dist: furo; extra == "dev"
79
- Requires-Dist: hypothesis!=6.102.0,!=6.112.3,>=6.85; extra == "dev"
80
- Requires-Dist: jsonpath_ng; extra == "dev"
81
- Requires-Dist: jupyter; extra == "dev"
82
- Requires-Dist: jupytext; extra == "dev"
83
- Requires-Dist: nbsphinx; extra == "dev"
84
- Requires-Dist: oil_reservoir_synthesizer; extra == "dev"
85
- Requires-Dist: pytest-asyncio; extra == "dev"
86
- Requires-Dist: pytest-benchmark; extra == "dev"
87
- Requires-Dist: pytest-cov; extra == "dev"
88
- Requires-Dist: pytest-memray; extra == "dev"
89
- Requires-Dist: pytest-mock; extra == "dev"
90
- Requires-Dist: pytest-mpl; extra == "dev"
91
- Requires-Dist: pytest-qt; extra == "dev"
92
- Requires-Dist: pytest-raises; extra == "dev"
93
- Requires-Dist: pytest-rerunfailures!=16.0; extra == "dev"
94
- Requires-Dist: pytest-snapshot; extra == "dev"
95
- Requires-Dist: pytest-timeout; extra == "dev"
96
- Requires-Dist: pytest-xdist; extra == "dev"
97
- Requires-Dist: pytest-durations; extra == "dev"
98
- Requires-Dist: pytest>6; extra == "dev"
99
- Requires-Dist: resdata; extra == "dev"
100
- Requires-Dist: rust-just; extra == "dev"
101
- Requires-Dist: scikit-image; extra == "dev"
102
- Requires-Dist: sphinx; extra == "dev"
103
- Requires-Dist: sphinx-argparse; extra == "dev"
104
- Requires-Dist: sphinx-autoapi; extra == "dev"
105
- Requires-Dist: sphinx-copybutton; extra == "dev"
106
- Requires-Dist: sphinxcontrib.datatemplates; extra == "dev"
107
- Requires-Dist: json-schema-for-humans; extra == "dev"
108
- Requires-Dist: xlsxwriter>=3.2.3; extra == "dev"
109
- Requires-Dist: resfo-utilities[testing]>=0.5.0; extra == "dev"
110
- Provides-Extra: style
111
- Requires-Dist: pre-commit; extra == "style"
112
- Provides-Extra: types
113
- Requires-Dist: mypy; extra == "types"
114
- Requires-Dist: types-lxml; extra == "types"
115
- Requires-Dist: types-requests; extra == "types"
116
- Requires-Dist: types-PyYAML; extra == "types"
117
- Requires-Dist: types-python-dateutil; extra == "types"
118
- Requires-Dist: types-decorator; extra == "types"
119
- Requires-Dist: types-docutils; extra == "types"
120
- Requires-Dist: types-tqdm; extra == "types"
121
- Requires-Dist: types-psutil; extra == "types"
122
- Requires-Dist: types-setuptools; extra == "types"
123
- Requires-Dist: types-networkx; extra == "types"
124
77
  Dynamic: license-file
125
78
 
126
79
  <h1 align="center">
@@ -184,7 +137,7 @@ Once uv is installed, you can get a development environment by running:
184
137
  ```sh
185
138
  git clone https://github.com/equinor/ert
186
139
  cd ert
187
- uv sync --all-extras
140
+ uv sync --all-groups
188
141
  ```
189
142
 
190
143
  ### Test setup