ert 19.0.0rc2__py3-none-any.whl → 19.0.0rc4__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.
@@ -36,7 +36,7 @@ if TYPE_CHECKING:
36
36
 
37
37
 
38
38
  DEFAULT_TIME_DELTA = timedelta(seconds=30)
39
- DEFAULT_LOCATION_RANGE_M = 3000
39
+ DEFAULT_LOCALIZATION_RADIUS = 3000
40
40
 
41
41
 
42
42
  def create_observation_dataframes(
@@ -205,6 +205,9 @@ def _handle_history_observation(
205
205
  "time": dates_series,
206
206
  "observations": pl.Series(values, dtype=pl.Float32),
207
207
  "std": pl.Series(std_dev, dtype=pl.Float32),
208
+ "east": pl.Series([None] * len(values), dtype=pl.Float32),
209
+ "north": pl.Series([None] * len(values), dtype=pl.Float32),
210
+ "radius": pl.Series([None] * len(values), dtype=pl.Float32),
208
211
  }
209
212
  )
210
213
 
@@ -297,40 +300,7 @@ def _get_restart(
297
300
 
298
301
 
299
302
  def _has_localization(summary_dict: SummaryObservation) -> bool:
300
- return any(
301
- [
302
- summary_dict.location_x is not None,
303
- summary_dict.location_y is not None,
304
- summary_dict.location_range is not None,
305
- ]
306
- )
307
-
308
-
309
- def _validate_localization_values(summary_dict: SummaryObservation) -> None:
310
- """The user must provide LOCATION_X and LOCATION_Y to use localization, while
311
- unprovided LOCATION_RANGE should default to some value.
312
-
313
- This method assumes the summary dict contains at least one LOCATION key.
314
- """
315
- if summary_dict.location_x is None or summary_dict.location_y is None:
316
- loc_values = {
317
- "LOCATION_X": summary_dict.location_x,
318
- "LOCATION_Y": summary_dict.location_y,
319
- "LOCATION_RANGE": summary_dict.location_range,
320
- }
321
- provided_loc_values = {k: v for k, v in loc_values.items() if v is not None}
322
-
323
- provided_loc_values_string = ", ".join(
324
- key.upper() for key in provided_loc_values
325
- )
326
- raise ObservationConfigError.with_context(
327
- f"Localization for observation {summary_dict.name} is misconfigured.\n"
328
- f"Only {provided_loc_values_string} were provided. To enable "
329
- f"localization for an observation, ensure that both LOCATION_X and "
330
- f"LOCATION_Y are defined - or remove LOCATION keywords to disable "
331
- f"localization.",
332
- summary_dict,
333
- )
303
+ return summary_dict.east is not None and summary_dict.north is not None
334
304
 
335
305
 
336
306
  def _handle_summary_observation(
@@ -370,23 +340,24 @@ def _handle_summary_observation(
370
340
  "Observation uncertainty must be strictly > 0", summary_key
371
341
  ) from None
372
342
 
373
- data_dict = {
374
- "response_key": [summary_key],
375
- "observation_key": [obs_key],
376
- "time": pl.Series([date]).dt.cast_time_unit("ms"),
377
- "observations": pl.Series([value], dtype=pl.Float32),
378
- "std": pl.Series([std_dev], dtype=pl.Float32),
379
- }
380
-
381
- if _has_localization(summary_dict):
382
- _validate_localization_values(summary_dict)
383
- data_dict["location_x"] = summary_dict.location_x
384
- data_dict["location_y"] = summary_dict.location_y
385
- data_dict["location_range"] = (
386
- summary_dict.location_range or DEFAULT_LOCATION_RANGE_M
387
- )
343
+ localization_radius = (
344
+ summary_dict.radius or DEFAULT_LOCALIZATION_RADIUS
345
+ if _has_localization(summary_dict)
346
+ else None
347
+ )
388
348
 
389
- return pl.DataFrame(data_dict)
349
+ return pl.DataFrame(
350
+ {
351
+ "response_key": [summary_key],
352
+ "observation_key": [obs_key],
353
+ "time": pl.Series([date]).dt.cast_time_unit("ms"),
354
+ "observations": pl.Series([value], dtype=pl.Float32),
355
+ "std": pl.Series([std_dev], dtype=pl.Float32),
356
+ "east": pl.Series([summary_dict.east], dtype=pl.Float32),
357
+ "north": pl.Series([summary_dict.north], dtype=pl.Float32),
358
+ "radius": pl.Series([localization_radius], dtype=pl.Float32),
359
+ }
360
+ )
390
361
 
391
362
 
392
363
  def _handle_general_observation(
@@ -514,6 +485,11 @@ def _handle_general_observation(
514
485
  "index": pl.Series(indices, dtype=pl.UInt16),
515
486
  "observations": pl.Series(values, dtype=pl.Float32),
516
487
  "std": pl.Series(stds, dtype=pl.Float32),
488
+ # Location attributes will always be None for general observations, but are
489
+ # necessary to concatenate with other observation dataframes.
490
+ "east": pl.Series([None] * len(values), dtype=pl.Float32),
491
+ "north": pl.Series([None] * len(values), dtype=pl.Float32),
492
+ "radius": pl.Series([None] * len(values), dtype=pl.Float32),
517
493
  }
518
494
  )
519
495
 
@@ -556,5 +532,6 @@ def _handle_rft_observation(
556
532
  "tvd": pl.Series([location[2]], dtype=pl.Float32),
557
533
  "observations": pl.Series([rft_observation.value], dtype=pl.Float32),
558
534
  "std": pl.Series([rft_observation.error], dtype=pl.Float32),
535
+ "radius": pl.Series([None], dtype=pl.Float32),
559
536
  }
560
537
  )
@@ -1,5 +1,4 @@
1
1
  import os
2
- from collections import Counter
3
2
  from collections.abc import Sequence
4
3
  from dataclasses import dataclass
5
4
  from enum import StrEnum
@@ -90,9 +89,9 @@ class _SummaryValues:
90
89
  name: str
91
90
  value: float
92
91
  key: str #: The :term:`summary key` in the summary response
93
- location_x: float | None = None
94
- location_y: float | None = None
95
- location_range: float | None = None
92
+ east: float | None = None
93
+ north: float | None = None
94
+ radius: float | None = None
96
95
 
97
96
 
98
97
  @dataclass
@@ -104,7 +103,7 @@ class SummaryObservation(ObservationDate, _SummaryValues, ObservationError):
104
103
 
105
104
  date_dict: ObservationDate = ObservationDate()
106
105
  float_values: dict[str, float] = {"ERROR_MIN": 0.1}
107
- localization_values: dict[str, float] = {}
106
+ localization_values: dict[str, float | None] = {}
108
107
  for key, value in observation_dict.items():
109
108
  match key:
110
109
  case "type" | "name":
@@ -125,12 +124,15 @@ class SummaryObservation(ObservationDate, _SummaryValues, ObservationError):
125
124
  summary_key = value
126
125
  case "DATE":
127
126
  date_dict.date = value
128
- case "LOCATION_X":
129
- localization_values["x"] = validate_float(value, key)
130
- case "LOCATION_Y":
131
- localization_values["y"] = validate_float(value, key)
132
- case "LOCATION_RANGE":
133
- localization_values["range"] = validate_float(value, key)
127
+ case "LOCALIZATION":
128
+ validate_localization(value, observation_dict["name"])
129
+ localization_values["east"] = validate_float(value["EAST"], key)
130
+ localization_values["north"] = validate_float(value["NORTH"], key)
131
+ localization_values["radius"] = (
132
+ validate_float(value["RADIUS"], key)
133
+ if "RADIUS" in value
134
+ else None
135
+ )
134
136
  case _:
135
137
  raise _unknown_key_error(str(key), observation_dict["name"])
136
138
  if "VALUE" not in float_values:
@@ -147,9 +149,9 @@ class SummaryObservation(ObservationDate, _SummaryValues, ObservationError):
147
149
  error_min=float_values["ERROR_MIN"],
148
150
  key=summary_key,
149
151
  value=float_values["VALUE"],
150
- location_x=localization_values.get("x"),
151
- location_y=localization_values.get("y"),
152
- location_range=localization_values.get("range"),
152
+ east=localization_values.get("east"),
153
+ north=localization_values.get("north"),
154
+ radius=localization_values.get("radius"),
153
155
  **date_dict.__dict__,
154
156
  )
155
157
 
@@ -324,25 +326,9 @@ def make_observations(
324
326
  if error_list:
325
327
  raise ObservationConfigError.from_collected(error_list)
326
328
 
327
- _validate_unique_names(result)
328
329
  return result
329
330
 
330
331
 
331
- def _validate_unique_names(
332
- observations: Sequence[Observation],
333
- ) -> None:
334
- names_counter = Counter(d.name for d in observations)
335
- duplicate_names = [n for n, c in names_counter.items() if c > 1]
336
- errors = [
337
- ErrorInfo(
338
- f"Duplicate observation name {n}",
339
- ).set_context(n)
340
- for n in duplicate_names
341
- ]
342
- if errors:
343
- raise ObservationConfigError.from_collected(errors)
344
-
345
-
346
332
  def _validate_segment_dict(name_token: str, inp: dict[str, Any]) -> Segment:
347
333
  start = None
348
334
  stop = None
@@ -415,6 +401,19 @@ def validate_positive_float(val: str, key: str) -> float:
415
401
  return v
416
402
 
417
403
 
404
+ def validate_localization(val: dict[str, Any], obs_name: str) -> None:
405
+ errors = []
406
+ if "EAST" not in val:
407
+ errors.append(_missing_value_error(f"LOCALIZATION for {obs_name}", "EAST"))
408
+ if "NORTH" not in val:
409
+ errors.append(_missing_value_error(f"LOCALIZATION for {obs_name}", "NORTH"))
410
+ for key in val:
411
+ if key not in {"EAST", "NORTH", "RADIUS"}:
412
+ errors.append(_unknown_key_error(key, f"LOCALIZATION for {obs_name}"))
413
+ if errors:
414
+ raise ObservationConfigError.from_collected(errors)
415
+
416
+
418
417
  def validate_positive_int(val: str, key: str) -> int:
419
418
  try:
420
419
  v = int(val)
ert/config/ert_config.py CHANGED
@@ -688,6 +688,14 @@ def log_observation_keys(
688
688
  if key not in {"name", "type"}
689
689
  )
690
690
 
691
+ if "HISTORY_OBSERVATION" in observation_type_counts:
692
+ msg = (
693
+ "HISTORY_OBSERVATION is deprecated and will be removed. "
694
+ "Please use SUMMARY_OBSERVATION instead."
695
+ )
696
+ ConfigWarning.warn(msg)
697
+ logger.warning(msg)
698
+
691
699
  logger.info(
692
700
  f"Count of observation types:\n\t{dict(observation_type_counts)}\n"
693
701
  f"Count of observation keywords:\n\t{dict(observation_keyword_counts)}"
@@ -138,6 +138,7 @@ observations_parser = Lark(
138
138
  PARAMETER_NAME : CHAR+
139
139
  object : "{" [(declaration";")*] "}"
140
140
  ?declaration: "SEGMENT" STRING object -> segment
141
+ | "LOCALIZATION" object -> localization
141
142
  | pair
142
143
  pair : PARAMETER_NAME "=" value
143
144
 
@@ -193,6 +194,11 @@ class TreeToObservations(Transformer[FileContextToken, list[ObservationDict]]):
193
194
  def segment(tree):
194
195
  return (("SEGMENT", tree[0]), tree[1])
195
196
 
197
+ @staticmethod
198
+ @no_type_check
199
+ def localization(tree):
200
+ return ("LOCALIZATION", tree[0])
201
+
196
202
  @staticmethod
197
203
  @no_type_check
198
204
  def object(tree):
@@ -84,6 +84,7 @@ async def get_observations_for_response(
84
84
  ensemble.experiment,
85
85
  obs_keys,
86
86
  json.loads(filter_on) if filter_on is not None else None,
87
+ requested_response_type=response_type,
87
88
  )
88
89
  if not obss:
89
90
  return []
@@ -107,10 +108,17 @@ def _get_observations(
107
108
  experiment: Experiment,
108
109
  observation_keys: list[str] | None = None,
109
110
  filter_on: dict[str, Any] | None = None,
111
+ requested_response_type: str | None = None,
110
112
  ) -> list[dict[str, Any]]:
111
113
  observations = []
112
114
 
113
- for response_type, df in experiment.observations.items():
115
+ for stored_response_type, df in experiment.observations.items():
116
+ if (
117
+ requested_response_type is not None
118
+ and stored_response_type != requested_response_type
119
+ ):
120
+ continue
121
+
114
122
  if observation_keys is not None:
115
123
  df = df.filter(pl.col("observation_key").is_in(observation_keys))
116
124
 
@@ -127,7 +135,7 @@ def _get_observations(
127
135
  if df.is_empty():
128
136
  continue
129
137
 
130
- x_axis_fn = response_to_pandas_x_axis_fns[response_type]
138
+ x_axis_fn = response_to_pandas_x_axis_fns[stored_response_type]
131
139
  df = df.rename(
132
140
  {
133
141
  "observation_key": "name",
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import io
3
4
  import operator
4
5
  import os
5
6
  from collections.abc import Iterator
@@ -257,6 +258,9 @@ def import_bgrdecl(
257
258
  raise ValueError(f"Did not find field parameter {field_name} in {file_path}")
258
259
 
259
260
 
261
+ _BUFFER_SIZE = 2**20 # 1.04 megabytes
262
+
263
+
260
264
  def export_grdecl(
261
265
  values: np.ma.MaskedArray[Any, np.dtype[np.float32]] | npt.NDArray[np.float32],
262
266
  file_path: str | os.PathLike[str],
@@ -271,12 +275,25 @@ def export_grdecl(
271
275
  if binary:
272
276
  resfo.write(file_path, [(param_name.ljust(8), values.astype(np.float32))])
273
277
  else:
274
- with open(file_path, "w", encoding="utf-8") as fh:
275
- fh.write(param_name + "\n")
276
- for i, v in enumerate(values):
277
- fh.write(" ")
278
- fh.write(f"{v:3e}")
279
- if i % 6 == 5:
280
- fh.write("\n")
281
-
282
- fh.write(" /\n")
278
+ length = values.shape[0]
279
+ per_line = 6
280
+ iters = 5
281
+ per_iter = per_line * iters
282
+ fmt = " ".join(["%3e"] * per_line)
283
+ fmt = "\n".join([fmt] * iters) + "\n"
284
+ with (
285
+ open(file_path, "wb+", 0) as fh,
286
+ io.BufferedWriter(fh, _BUFFER_SIZE) as bw,
287
+ io.TextIOWrapper(bw, write_through=True, encoding="utf-8") as tw,
288
+ ):
289
+ tw.write(param_name + "\n")
290
+ i = 0
291
+ while i + per_iter <= length:
292
+ tw.write(fmt % tuple(values[i : i + per_iter]))
293
+ i += per_iter
294
+
295
+ for j, v in enumerate(values[length - (length % per_iter) :]):
296
+ tw.write(f" {v:3e}")
297
+ if j % 6 == 5:
298
+ tw.write("\n")
299
+ tw.write(" /\n")
@@ -223,9 +223,12 @@ class _EnsembleWidget(QWidget):
223
223
  return
224
224
 
225
225
  observation_key = selected.data(1, Qt.ItemDataRole.DisplayRole)
226
- if not observation_key:
226
+ parent = selected.parent()
227
+
228
+ if not observation_key or not parent:
227
229
  return
228
230
 
231
+ response_type = parent.data(0, Qt.ItemDataRole.UserRole)
229
232
  observation_label = selected.data(0, Qt.ItemDataRole.DisplayRole)
230
233
  assert self._ensemble is not None
231
234
  observations_dict = self._ensemble.experiment.observations
@@ -235,17 +238,7 @@ class _EnsembleWidget(QWidget):
235
238
  ax.set_title(observation_key)
236
239
  ax.grid(True)
237
240
 
238
- response_type, obs_for_type = next(
239
- (
240
- (response_type, df)
241
- for response_type, df in observations_dict.items()
242
- if observation_key in df["observation_key"]
243
- ),
244
- (None, None),
245
- )
246
-
247
- assert response_type is not None
248
- assert obs_for_type is not None
241
+ obs_for_type = observations_dict[response_type]
249
242
 
250
243
  response_config = self._ensemble.experiment.response_configuration[
251
244
  response_type
@@ -377,14 +370,23 @@ class _EnsembleWidget(QWidget):
377
370
  .to_numpy()
378
371
  ):
379
372
  match_list = self._observations_tree_widget.findItems(
380
- response_key, Qt.MatchFlag.MatchExactly
373
+ response_key, Qt.MatchFlag.MatchExactly, 0
381
374
  )
382
- if len(match_list) == 0:
375
+
376
+ root = next(
377
+ (
378
+ item
379
+ for item in match_list
380
+ if item.data(0, Qt.ItemDataRole.UserRole) == response_type
381
+ ),
382
+ None,
383
+ )
384
+
385
+ if root is None:
383
386
  root = QTreeWidgetItem(
384
387
  self._observations_tree_widget, [response_key]
385
388
  )
386
- else:
387
- root = match_list[0]
389
+ root.setData(0, Qt.ItemDataRole.UserRole, response_type)
388
390
 
389
391
  obs_ds = obs_ds_for_type.filter(
390
392
  pl.col("observation_key").eq(obs_key)
@@ -400,9 +402,7 @@ class _EnsembleWidget(QWidget):
400
402
  ],
401
403
  )
402
404
 
403
- self._observations_tree_widget.sortItems(
404
- 0, Qt.SortOrder.AscendingOrder
405
- )
405
+ self._observations_tree_widget.sortItems(0, Qt.SortOrder.AscendingOrder)
406
406
 
407
407
  for i in range(self._observations_tree_widget.topLevelItemCount()):
408
408
  item = self._observations_tree_widget.topLevelItem(i)
@@ -163,6 +163,7 @@ class PlotWidget(QWidget):
163
163
  vbox.addSpacing(8)
164
164
  self.setLayout(vbox)
165
165
 
166
+ self._negative_values_in_data = False
166
167
  self._dirty = True
167
168
  self._active = False
168
169
  self.resetPlot()
@@ -175,11 +176,15 @@ class PlotWidget(QWidget):
175
176
  self._figure.clear()
176
177
 
177
178
  def _sync_log_checkbox(self) -> None:
178
- if type(self._plotter).__name__ in {
179
- "HistogramPlot",
180
- "DistributionPlot",
181
- "GaussianKDEPlot",
182
- }:
179
+ if (
180
+ type(self._plotter).__name__
181
+ in {
182
+ "HistogramPlot",
183
+ "DistributionPlot",
184
+ "GaussianKDEPlot",
185
+ }
186
+ and self._negative_values_in_data is False
187
+ ):
183
188
  self._log_checkbox.setVisible(True)
184
189
  else:
185
190
  self._log_checkbox.setVisible(False)
@@ -198,8 +203,11 @@ class PlotWidget(QWidget):
198
203
  ) -> None:
199
204
  self.resetPlot()
200
205
  try:
206
+ self._sync_log_checkbox()
201
207
  plot_context.log_scale = (
202
- self._log_checkbox.isVisible() and self._log_checkbox.isChecked()
208
+ self._log_checkbox.isVisible()
209
+ and self._log_checkbox.isChecked()
210
+ and self._negative_values_in_data is False
203
211
  )
204
212
  self._plotter.plot(
205
213
  self._figure,
@@ -210,7 +218,6 @@ class PlotWidget(QWidget):
210
218
  key_def,
211
219
  )
212
220
  self._canvas.draw()
213
- self._sync_log_checkbox()
214
221
  except Exception as e:
215
222
  exc_type, _, exc_tb = sys.exc_info()
216
223
  sys.stderr.write("-" * 80 + "\n")
@@ -284,6 +284,15 @@ class PlotWindow(QMainWindow):
284
284
  except BaseException as e:
285
285
  handle_exception(e)
286
286
 
287
+ negative_values_in_data = False
288
+ if key_def.parameter is not None and key_def.parameter.type == "gen_kw":
289
+ for data in ensemble_to_data_map.values():
290
+ data = data.T
291
+ if data.le(0).any().any():
292
+ negative_values_in_data = True
293
+ break
294
+
295
+ plot_widget._negative_values_in_data = negative_values_in_data
287
296
  observations = None
288
297
  if key_def.observations and selected_ensembles:
289
298
  try:
ert/shared/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '19.0.0rc2'
32
- __version_tuple__ = version_tuple = (19, 0, 0, 'rc2')
31
+ __version__ = version = '19.0.0rc4'
32
+ __version_tuple__ = version_tuple = (19, 0, 0, 'rc4')
33
33
 
34
- __commit_id__ = commit_id = 'g0135983dc'
34
+ __commit_id__ = commit_id = 'g2518c4485'
@@ -679,6 +679,9 @@ class LocalEnsemble(BaseMode):
679
679
  if complete_df is None:
680
680
  complete_df = ds
681
681
  else:
682
+ complete_df = complete_df.drop(
683
+ [c for c in ds.columns if c != "realization"], strict=False
684
+ )
682
685
  complete_df = (
683
686
  complete_df.join(ds, on="realization", how="left")
684
687
  .unique(subset=["realization"], keep="first")
@@ -1096,6 +1099,11 @@ class LocalEnsemble(BaseMode):
1096
1099
  on=["response_key", *response_cls.primary_key],
1097
1100
  )
1098
1101
 
1102
+ # Do not drop primary keys which
1103
+ # overlap with localization attributes
1104
+ primary_keys_to_drop = set(response_cls.primary_key).difference(
1105
+ {"north", "east", "radius"}
1106
+ )
1099
1107
  joined = (
1100
1108
  joined.with_columns(
1101
1109
  pl.concat_str(
@@ -1105,7 +1113,7 @@ class LocalEnsemble(BaseMode):
1105
1113
  # Avoid potential collisions w/ primary key
1106
1114
  )
1107
1115
  )
1108
- .drop(response_cls.primary_key)
1116
+ .drop(primary_keys_to_drop)
1109
1117
  .rename({"__tmp_index_key__": "index"})
1110
1118
  )
1111
1119
 
@@ -1121,6 +1129,9 @@ class LocalEnsemble(BaseMode):
1121
1129
  "observation_key",
1122
1130
  "observations",
1123
1131
  "std",
1132
+ "east",
1133
+ "north",
1134
+ "radius",
1124
1135
  ]
1125
1136
  )
1126
1137
 
@@ -31,7 +31,7 @@ from .realization_storage_state import RealizationStorageState
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
 
34
- _LOCAL_STORAGE_VERSION = 21
34
+ _LOCAL_STORAGE_VERSION = 23
35
35
 
36
36
 
37
37
  class _Migrations(BaseModel):
@@ -517,6 +517,8 @@ class LocalStorage(BaseMode):
517
517
  to19,
518
518
  to20,
519
519
  to21,
520
+ to22,
521
+ to23,
520
522
  )
521
523
 
522
524
  try:
@@ -567,6 +569,8 @@ class LocalStorage(BaseMode):
567
569
  18: to19,
568
570
  19: to20,
569
571
  20: to21,
572
+ 21: to22,
573
+ 22: to23,
570
574
  }
571
575
  for from_version in range(version, _LOCAL_STORAGE_VERSION):
572
576
  migrations[from_version].migrate(self.path)
@@ -0,0 +1,18 @@
1
+ from pathlib import Path
2
+
3
+ import polars as pl
4
+
5
+ info = "Add default None values to summary observations LOCATION keywords"
6
+
7
+
8
+ def migrate(path: Path) -> None:
9
+ for summary_observation in path.glob("experiments/*/observations/summary"):
10
+ summary_df = pl.read_parquet(summary_observation)
11
+
12
+ for location_kw in ["location_x", "location_y", "location_range"]:
13
+ if location_kw not in summary_df.columns:
14
+ summary_df = summary_df.with_columns(
15
+ pl.lit(None, dtype=pl.Float32).alias(location_kw)
16
+ )
17
+
18
+ summary_df.write_parquet(summary_observation)
@@ -0,0 +1,49 @@
1
+ from pathlib import Path
2
+
3
+ import polars as pl
4
+
5
+ info = "Add default None values to summary observations LOCATION keywords"
6
+
7
+ old_localization_keywords = ["location_x", "location_y", "location_range"]
8
+ new_localization_keywords = ["east", "north", "radius"]
9
+
10
+
11
+ def migrate(path: Path) -> None:
12
+ for gen_obs in path.glob("experiments/*/observations/gen_data"):
13
+ gen_obs_df = pl.read_parquet(gen_obs)
14
+
15
+ for new_kw in new_localization_keywords:
16
+ if new_kw not in gen_obs_df.columns:
17
+ gen_obs_df = gen_obs_df.with_columns(
18
+ pl.lit(None, dtype=pl.Float32).alias(new_kw)
19
+ )
20
+
21
+ gen_obs_df.write_parquet(gen_obs)
22
+
23
+ for rft_obs in path.glob("experiments/*/observations/rft"):
24
+ rft_obs_df = pl.read_parquet(rft_obs)
25
+
26
+ for new_kw in new_localization_keywords:
27
+ if new_kw not in rft_obs_df.columns:
28
+ rft_obs_df = rft_obs_df.with_columns(
29
+ pl.lit(None, dtype=pl.Float32).alias(new_kw)
30
+ )
31
+
32
+ rft_obs_df.write_parquet(rft_obs)
33
+
34
+ for summary_obs in path.glob("experiments/*/observations/summary"):
35
+ summary_df = pl.read_parquet(summary_obs)
36
+
37
+ for old_kw, new_kw in zip(
38
+ old_localization_keywords, new_localization_keywords, strict=True
39
+ ):
40
+ if old_kw in summary_df.columns:
41
+ column = summary_df[old_kw]
42
+ summary_df = summary_df.with_columns(column.alias(new_kw))
43
+ summary_df = summary_df.drop(old_kw)
44
+ else:
45
+ summary_df = summary_df.with_columns(
46
+ pl.lit(None, dtype=pl.Float32).alias(new_kw)
47
+ )
48
+
49
+ summary_df.write_parquet(summary_obs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ert
3
- Version: 19.0.0rc2
3
+ Version: 19.0.0rc4
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
@@ -42,10 +42,10 @@ ert/cli/main.py,sha256=oWiIUF5r2E1QOforFY-nQ2k3mrE74EDqrk8QcjcdfmE,6567
42
42
  ert/cli/monitor.py,sha256=ad6aT1Ch-To5XpQR6eR1SMCBZ9HNRjPE9X8o6TEGURg,5973
43
43
  ert/cli/workflow.py,sha256=QKbpHr_Tc5NQjSNL1tB4uCo9ykTkqvwohywbjGAm-r4,1260
44
44
  ert/config/__init__.py,sha256=RVLt_v8nF9xjG51smLK9OXZT6yAH5KEmSgnFYYvVogU,4310
45
- ert/config/_create_observation_dataframes.py,sha256=P-cyJlushUR4Em58rRAsmK3jw3PoYhbqsT5qsHrpL7c,19717
45
+ ert/config/_create_observation_dataframes.py,sha256=FHwTXR6awIFkVxdxOGdy6QQuar_lz4C7oBw_lPCox8E,19099
46
46
  ert/config/_design_matrix_validator.py,sha256=_eEk07L4c7sv8WwTYYGHc_rT1HEOZDqLrgla0r9rpj0,1308
47
47
  ert/config/_get_num_cpu.py,sha256=IXOEHkGJEz7kEOysc29q-jpaXqbWeu-Y4FlQvGp0ryM,7684
48
- ert/config/_observations.py,sha256=EUWQCEMqEpJgmQYvGrvyOIF25nu6w566XV-vw7QPqjU,14814
48
+ ert/config/_observations.py,sha256=nm6GsFAwh16anXDuz04p9jn6sT4hd233Do7H__QpATY,15000
49
49
  ert/config/_read_summary.py,sha256=_1f6iZV2tBDRtPn5C_29cyjN7suA5hh1HnLKyF9L4jY,7500
50
50
  ert/config/_str_to_bool.py,sha256=AxNCJAuTtKF-562CRh7HgjQIyM7N-jjSlRJKvpCNk9I,852
51
51
  ert/config/analysis_config.py,sha256=v-ZppIlP_NkmhtuYuxm31m2V3eA7YjvC3rDsMXm5qPk,8646
@@ -54,7 +54,7 @@ ert/config/capture_validation.py,sha256=8HGEbJ2z9FXeEaxSewejP7NtEh4LLomPwcdpC0CJ
54
54
  ert/config/design_matrix.py,sha256=yyAFBppTwZXt4OeN6kxRmLk16jF8bntQWLHU_-rDQn4,17236
55
55
  ert/config/distribution.py,sha256=rzpO-U8c2ptsj1KlfUw6n_CRaj-e1cvzVvasR0t5sZI,12728
56
56
  ert/config/ensemble_config.py,sha256=b0KuQ_y85kr4AOPPX_qieYKgnDGZ4_87bSjYpVZuOlM,7322
57
- ert/config/ert_config.py,sha256=_UXsCXU_aV_IBqfQEuDGOT9ylopjpWrThDaYVwIWweA,57147
57
+ ert/config/ert_config.py,sha256=jLiqGYLA-lBlnHoh6tmWa1kZE6LT11gwoSZD-eLEYCs,57415
58
58
  ert/config/ert_plugin.py,sha256=hENwrc9FfhqUYjVpFYcmy66jDLgU_gagOJFBcYjxe6A,458
59
59
  ert/config/ert_script.py,sha256=64FZ-dMI8DZtRLHWReC19KY-ZOsBhdgYkwAe9ZWLc_I,8405
60
60
  ert/config/everest_control.py,sha256=-bwFEb_GpdodQ3N_BscQdcKatMlWBs8UVSCDURV8Q3s,8072
@@ -99,7 +99,7 @@ ert/config/parsing/forward_model_schema.py,sha256=m2a9rVVPbw8HusoIv5bgrGbnPVKt-9
99
99
  ert/config/parsing/history_source.py,sha256=z-DCe5TS3egxSXoK1kOIXC2IWL70kUhQNtzfTWsl8iU,141
100
100
  ert/config/parsing/hook_runtime.py,sha256=f1rRgYOXl6HY0acMNT0am5cdS-5cJFA0FnCausoEDmA,315
101
101
  ert/config/parsing/lark_parser.py,sha256=SS0yXTI5w_qmpFvePMO-r0g9NPqOOrlCFF3amPefnLM,15930
102
- ert/config/parsing/observations_parser.py,sha256=35l2UdX3mBPh51wOjyUnruo5FdH5YOxqQ1X6TuRMYyQ,6792
102
+ ert/config/parsing/observations_parser.py,sha256=idpvJGkP72eO3P95g3kwKjovZS9C1loDQAclDRlFAbU,6955
103
103
  ert/config/parsing/queue_system.py,sha256=2bFuVc1JSVyE3gnBnN4YsUXHfLHeWAtasnPPCu9Za_w,793
104
104
  ert/config/parsing/schema_dict.py,sha256=MWKhtLhdRvqfWm8oZatWFnAhiIU03DdQCOaX6A71068,4313
105
105
  ert/config/parsing/schema_item_type.py,sha256=LP6lXE7YihnAEVP3kCJ80kdpgH6Veu--xcPfgaqJhdc,653
@@ -122,7 +122,7 @@ ert/dark_storage/endpoints/__init__.py,sha256=o093-GLgw8br7PDKhHna0LviXeJQdC5P1R
122
122
  ert/dark_storage/endpoints/ensembles.py,sha256=22M358HTAjiNuKaRYp9FZ3SZvkWL3v9wMDD0DGwLF8M,1363
123
123
  ert/dark_storage/endpoints/experiment_server.py,sha256=snaCwRXayGn6_SIqH49Qmi4u1ZILiH2ynFZL6L4YsxQ,14118
124
124
  ert/dark_storage/endpoints/experiments.py,sha256=_tY95HzW6ibJy7N9C-1XICFHSOrKdz4vM3bv7ePRvY8,3413
125
- ert/dark_storage/endpoints/observations.py,sha256=EpetZi7cjlrexfU9VPdiTJV1PT6k0ZNx366WGlfKZM4,4574
125
+ ert/dark_storage/endpoints/observations.py,sha256=gnww5S1B9G8vAw7AwcR1fgW_vFgyf5WlU1gOSUXW1i4,4841
126
126
  ert/dark_storage/endpoints/parameters.py,sha256=LERil7H-L3ZsPGGFm97kvy3XeIqpceyBe5aSFLkSVEY,4406
127
127
  ert/dark_storage/endpoints/responses.py,sha256=tFEdgqP1vcOuRPmr4YpE9okEpxowXMoYjYdUq2wljZ8,6195
128
128
  ert/dark_storage/endpoints/updates.py,sha256=BWEh2XUTqdsPPEtiSE8bJtXcFVzw-GlbKIK3vvc_Cu8,142
@@ -151,7 +151,7 @@ ert/exceptions/_exceptions.py,sha256=dv4rs5oWe00PcelvGEsTscD3AKhI1uwwSjprMSHk4xw
151
151
  ert/field_utils/__init__.py,sha256=bnjVYQq0A1lkTUSDUHU8pBtnkQmvdw-zrtFhUT41FW4,768
152
152
  ert/field_utils/field_file_format.py,sha256=QWDQYsba2zUfbMltBxReZqAZOYWkHb8kG_xY7BvBzO0,297
153
153
  ert/field_utils/field_utils.py,sha256=Z6mbMHLNyCPdPDyD01Z_myLXfiki3j9MkT08S4awVuk,16791
154
- ert/field_utils/grdecl_io.py,sha256=kgSE3Fyr_7KDS1HQRmO7RQLMwgrkgJ_Tsmo7jE9GE1s,8971
154
+ ert/field_utils/grdecl_io.py,sha256=QbRbcZIfNyRliMwyFwmUnMIHc4Za9-uUSitm4l3uT0k,9521
155
155
  ert/field_utils/roff_io.py,sha256=m4RX2134kVbEkuPjIY5OthavRe4kNirtL4jNdEf_xpU,4014
156
156
  ert/gui/__init__.py,sha256=Q-BjtVNAk8Kw2hcPMlCkbTOSjNZPzSX5xl0tFUUI2bY,689
157
157
  ert/gui/about_dialog.py,sha256=H0Jfso2v9s1eONTVgghH84UcaUlwVs0Cqqbv17Hvw4g,3127
@@ -263,7 +263,7 @@ ert/gui/tools/load_results/load_results_tool.py,sha256=deP__dGX8z5iycPMYv3cYyOta
263
263
  ert/gui/tools/manage_experiments/__init__.py,sha256=MAB41GPqlpALPYRvFFpKCcr2Sz3cya7Grd88jLxUj2A,99
264
264
  ert/gui/tools/manage_experiments/export_dialog.py,sha256=tWtttCLqr4T0HK9uEtM8JUubBLvytn_A2cZRZBvJ1AI,4485
265
265
  ert/gui/tools/manage_experiments/manage_experiments_panel.py,sha256=EUGOo68g8E9f4oG3K4MFRCu8a7rm7ojOF6jUvz_dqic,5680
266
- ert/gui/tools/manage_experiments/storage_info_widget.py,sha256=UBlnF8sqCTliV-FeNILBBKtwXJGY3PjPIaaM8xAptFM,19861
266
+ ert/gui/tools/manage_experiments/storage_info_widget.py,sha256=J3Xm59mQ6VIYTrwCkhKzZqojrBtncxgEI_f_nLfbFF4,19940
267
267
  ert/gui/tools/manage_experiments/storage_model.py,sha256=wf5JPqvbFWLI9ZcVTc4gpZh3hUPDNwOxRdbdcRtjKCc,6802
268
268
  ert/gui/tools/manage_experiments/storage_widget.py,sha256=pe5mWOgw-uNGXaZYhl1JsF5--Krz1W4n3Ut4sRcx6uc,6692
269
269
  ert/gui/tools/plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -272,8 +272,8 @@ ert/gui/tools/plot/data_type_keys_widget.py,sha256=AgJh_7vfXFKzzzCMq8pxhldkzuhBt
272
272
  ert/gui/tools/plot/data_type_proxy_model.py,sha256=DGj7GsDwbvr2OUIudmQpdnoqtPeWyKVJHlctxl1TzzQ,2176
273
273
  ert/gui/tools/plot/plot_api.py,sha256=8nkfFZJENIrHI-yWwHnrg01AOjYGiV3eE1Qfj-7aUTI,16361
274
274
  ert/gui/tools/plot/plot_ensemble_selection_widget.py,sha256=WnXsI5SwIklPvlkJ_02qjv6T8pDhXVStiHqerD53u_4,7619
275
- ert/gui/tools/plot/plot_widget.py,sha256=w_avqCvBe68rvZXOa4WiFC2IsXSbIAYOGEZhHtzFeiA,7527
276
- ert/gui/tools/plot/plot_window.py,sha256=_9KgIi_jbNNUnOW80DkCJb1GACStYRQ7BZYAq2fE7Hs,17327
275
+ ert/gui/tools/plot/plot_widget.py,sha256=kQvX89b4z2TAwXIzRuDEDnfJNq-jMyTC8Lzyn8T0HwU,7755
276
+ ert/gui/tools/plot/plot_window.py,sha256=gZZCDLVcFJ-HPVYRaQcNQoYmJ3IRWEXi1_z6HJm97Es,17757
277
277
  ert/gui/tools/plot/customize/__init__.py,sha256=spAW99ubzOmWuScii_idW0frGDttKCcT4XQegF3vOSU,151
278
278
  ert/gui/tools/plot/customize/color_chooser.py,sha256=fxrXEFCCvHwJnE0pQMELIy0torqSNATnARx6hBgSV5E,2576
279
279
  ert/gui/tools/plot/customize/customization_view.py,sha256=er1PQnhePTs43dsB9gDV7nkMDV0tDmqFneHG7R5UDkM,5093
@@ -397,7 +397,7 @@ ert/services/ert_server.py,sha256=qIzqugIHcxwKuzjkItiMt3jah3hNI7x3NQ3p_WBBf_o,10
397
397
  ert/services/webviz_ert_service.py,sha256=J5vznqb_-DjlDMOze7tdvuBE4GWEPgJ5dIIXvRLKd0Y,650
398
398
  ert/shared/__init__.py,sha256=OwgL-31MxA0fabETJ5Svw0tqJpHi569CZDRFHdHiqA0,644
399
399
  ert/shared/net_utils.py,sha256=Wp9Qyd5wWNHPU0Myh1GCbUONu0a-akYEdJ07MjQJt4I,6130
400
- ert/shared/version.py,sha256=a08nnfTcfo2JoiO9C_qp7fS-7EAD96k6QDqcATgTKd4,724
400
+ ert/shared/version.py,sha256=KsmvkbSRbh0t0L3rD-7UvoIOd2pj2KF4yMF-pmHEnYk,724
401
401
  ert/shared/_doc_utils/__init__.py,sha256=09KMJxjza26BXouUy6yJmMiSuYFGSI6c8nZ-1_qXh90,995
402
402
  ert/shared/_doc_utils/ert_jobs.py,sha256=uHP8ozhKwCHG6BkyhAgCGoy59JEFb102pHKot-5ZEys,8054
403
403
  ert/shared/_doc_utils/everest_jobs.py,sha256=uBDN7tIwlBJIZVZ6ZFL1tkewEJJGDLoeVrFIIrJznvM,2081
@@ -414,9 +414,9 @@ ert/shared/storage/connection.py,sha256=Y5P8B8B__j3doE9UE-1QROFYwrLcrmFcG80LhGTd
414
414
  ert/shared/storage/extraction.py,sha256=52Nyh2SITXIglEBMIRcW2a_iqJL3OdAf_dWMY0plTZE,1307
415
415
  ert/storage/__init__.py,sha256=f4uzzomaB1TpFpzGMF2Jd_PV54lq4EfkiZzQApDBuPQ,2110
416
416
  ert/storage/load_status.py,sha256=7h_GdA2qYGgQ-M5AOIo7xG43ljwzEEgbRb7vg0xSYEE,304
417
- ert/storage/local_ensemble.py,sha256=m3p8pUG8mYzYO8l_tnhjlVvhQwvPp97ztUNDO4Zjd1s,50965
417
+ ert/storage/local_ensemble.py,sha256=t88F0ZdmduD6_tUhc78X1HxhEXuJUZnRaIQicdq42yk,51513
418
418
  ert/storage/local_experiment.py,sha256=JNdTQWn0jJLqN8pYeh4XbuSxxiTN5Qbc0nkJzzgjhAU,16871
419
- ert/storage/local_storage.py,sha256=oDdhtQkuKXrmXiFX-RKSoyfHwSWkS1M61yZZvmJQJQ0,24011
419
+ ert/storage/local_storage.py,sha256=Ni2IThA8jWeRsYmF1n56cHjcDIx4GTCZR2mo0kyFqjE,24107
420
420
  ert/storage/mode.py,sha256=GJBlRSqS0Q06qDvaAztdcG-oV2MLsVID2Mo3OgQKjUw,2470
421
421
  ert/storage/realization_storage_state.py,sha256=JdiBr__Ce5e1MzmRsRdMuwgCtiuHZRjsQ-as8ivTX7Q,220
422
422
  ert/storage/migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -432,6 +432,8 @@ ert/storage/migration/to18.py,sha256=R6ou46jS-R03WJKB4ZeHTehzTsxH4df2QsJ9wczeQPk
432
432
  ert/storage/migration/to19.py,sha256=1FmfNeXBW149W07u78AyU39g57TXXNl-fG9c4kqlIpU,1090
433
433
  ert/storage/migration/to20.py,sha256=DZ79hfJxdbaewP4W8TyRdsQvi-FkeSco_0uZKBdyD_4,697
434
434
  ert/storage/migration/to21.py,sha256=ArUePLN6placVlgKFS2Fi1kWD4qQZ1bsJGOxYMmhCP0,811
435
+ ert/storage/migration/to22.py,sha256=UxPy5i5o0UzNk9chY024PmwbHMdJCXCngmsquG_yGkI,622
436
+ ert/storage/migration/to23.py,sha256=ynhYCm1yZEUvCmJpSBNrElzpGLOKpb29IjSe-Dd8azg,1740
435
437
  ert/storage/migration/to6.py,sha256=Pj9lVCyPCOP0-dt4uypsZtS5Awbc8B7oaySu_VTwnnA,1514
436
438
  ert/storage/migration/to7.py,sha256=hV5lLfaQegyvxsy_lWfsiQAYVPCvS8Oe0fYc_fvKXzY,4500
437
439
  ert/storage/migration/to8.py,sha256=VL7A5KWTSFhBWmx3n-vCKBaEd2U8SUqyz8vPieyVd9E,5390
@@ -453,7 +455,7 @@ ert/validation/validation_status.py,sha256=f47_B7aS-9DEh6uaVzKxD97pXienkyTVVCqTy
453
455
  ert/warnings/__init__.py,sha256=IBwQVkdD7Njaad9PAB-9K-kr15wnA4EBKboxyqgu9NA,214
454
456
  ert/warnings/_warnings.py,sha256=7qhNZ0W4nnljzoOx6AXX7VlMv5pa34Ek5M5n1Ep0Kak,189
455
457
  ert/warnings/specific_warning_handler.py,sha256=5dVXtOhzcMmtPBGx4AOddXNPfzTFOPA7RVtdH8hLv68,932
456
- ert-19.0.0rc2.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
458
+ ert-19.0.0rc4.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
457
459
  everest/__init__.py,sha256=8_f50f6H3-onqaiuNCwC0Eiotdl9JuTxhwyF_54MVvU,306
458
460
  everest/config_file_loader.py,sha256=rOHYvB4ayB2MaKdaAynvJVtbCOqi_z25EdwEqJ02-DQ,5675
459
461
  everest/everest_storage.py,sha256=c3sgU7-3BDSRXxJfCR_4F58rWEaoII1wygz6VvM-GGI,42025
@@ -517,8 +519,8 @@ everest/templates/well_drill.tmpl,sha256=9iLexmBHMsMQNXyyRK4GlmVuVpVIxRcCHpy1av5
517
519
  everest/templates/well_order.tmpl,sha256=XJ1eVRkeyTdLu5sLsltJSSK6BDLN7rFOAqLdM3ZZy3w,75
518
520
  everest/util/__init__.py,sha256=xEYLz6pUtgkH8VHer1RfoCwKiO70dBnuhHonsOPaOx0,1359
519
521
  everest/util/forward_models.py,sha256=JPxHhLI6TrmQJwW50wwGBmw57TfRd8SG2svYhXFHrc8,1617
520
- ert-19.0.0rc2.dist-info/METADATA,sha256=QR91Z6CbWwTQrNCHBDThQE71MzA8wXXFkUS9Fct4eJ0,10015
521
- ert-19.0.0rc2.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
522
- ert-19.0.0rc2.dist-info/entry_points.txt,sha256=ChZ7vn8Qy9v9rT8GM2JtAvWDN3NVoy4BIcvVRtU73CM,189
523
- ert-19.0.0rc2.dist-info/top_level.txt,sha256=LRh9GfdfyDWfAGmrQgp_XdoMHA4v6aotw8xgsy5YyHE,17
524
- ert-19.0.0rc2.dist-info/RECORD,,
522
+ ert-19.0.0rc4.dist-info/METADATA,sha256=G819IMtndapqr2Vhl69WeFq80kwSdEdtFcDlKGJsvdo,10015
523
+ ert-19.0.0rc4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
524
+ ert-19.0.0rc4.dist-info/entry_points.txt,sha256=ChZ7vn8Qy9v9rT8GM2JtAvWDN3NVoy4BIcvVRtU73CM,189
525
+ ert-19.0.0rc4.dist-info/top_level.txt,sha256=LRh9GfdfyDWfAGmrQgp_XdoMHA4v6aotw8xgsy5YyHE,17
526
+ ert-19.0.0rc4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5