ert 17.1.9__py3-none-any.whl → 18.0.1__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/__main__.py +8 -7
- ert/analysis/_update_commons.py +12 -3
- ert/cli/main.py +6 -3
- ert/cli/monitor.py +7 -0
- ert/config/__init__.py +13 -3
- ert/config/_create_observation_dataframes.py +60 -12
- ert/config/_observations.py +14 -1
- ert/config/_read_summary.py +8 -6
- ert/config/ensemble_config.py +6 -14
- ert/config/ert_config.py +19 -13
- ert/config/{everest_objective_config.py → everest_response.py} +23 -12
- ert/config/ext_param_config.py +133 -1
- ert/config/field.py +12 -8
- ert/config/forward_model_step.py +108 -6
- ert/config/gen_data_config.py +2 -6
- ert/config/gen_kw_config.py +0 -9
- ert/config/known_response_types.py +14 -0
- ert/config/parameter_config.py +0 -17
- ert/config/parsing/config_keywords.py +1 -0
- ert/config/parsing/config_schema.py +12 -0
- ert/config/parsing/config_schema_deprecations.py +11 -0
- ert/config/parsing/config_schema_item.py +1 -1
- ert/config/queue_config.py +4 -4
- ert/config/response_config.py +0 -7
- ert/config/rft_config.py +230 -0
- ert/config/summary_config.py +2 -6
- ert/config/violations.py +0 -0
- 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/compute/misfits.py +7 -6
- ert/dark_storage/endpoints/compute/misfits.py +2 -2
- ert/dark_storage/endpoints/observations.py +4 -4
- ert/dark_storage/endpoints/responses.py +15 -1
- ert/ensemble_evaluator/__init__.py +8 -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 +211 -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/searchbox.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
- ert/gui/main.py +14 -7
- ert/gui/main_window.py +1 -2
- 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 +1 -1
- 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 +25 -4
- ert/gui/simulation/single_test_run_panel.py +2 -2
- ert/gui/summarypanel.py +1 -1
- ert/gui/tools/load_results/load_results_panel.py +1 -1
- ert/gui/tools/manage_experiments/storage_info_widget.py +7 -7
- ert/gui/tools/manage_experiments/storage_widget.py +1 -2
- ert/gui/tools/plot/plot_api.py +13 -10
- ert/gui/tools/plot/plot_window.py +12 -0
- 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/ensemble.py +9 -2
- ert/gui/tools/plot/plottery/plots/statistics.py +59 -19
- ert/mode_definitions.py +2 -0
- ert/plugins/__init__.py +0 -1
- 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 +2 -33
- ert/resources/shell_scripts/delete_directory.py +2 -2
- ert/run_models/__init__.py +18 -5
- ert/run_models/_create_run_path.py +33 -21
- 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 +155 -44
- ert/run_models/initial_ensemble_run_model.py +23 -22
- ert/run_models/manual_update.py +4 -2
- ert/run_models/manual_update_enif.py +37 -0
- ert/run_models/model_factory.py +81 -22
- ert/run_models/multiple_data_assimilation.py +21 -10
- ert/run_models/run_model.py +54 -34
- 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 +31 -15
- ert/services/ert_server.py +317 -0
- ert/shared/_doc_utils/ert_jobs.py +1 -4
- ert/shared/storage/connection.py +3 -3
- ert/shared/version.py +3 -3
- ert/storage/local_ensemble.py +25 -5
- ert/storage/local_experiment.py +6 -14
- ert/storage/local_storage.py +36 -30
- ert/storage/migration/to18.py +12 -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-17.1.9.dist-info → ert-18.0.1.dist-info}/METADATA +8 -7
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/RECORD +159 -158
- everest/bin/config_branch_script.py +3 -6
- everest/bin/everconfigdump_script.py +1 -9
- everest/bin/everest_script.py +21 -11
- everest/bin/kill_script.py +2 -2
- everest/bin/monitor_script.py +2 -2
- everest/bin/utils.py +6 -3
- everest/config/__init__.py +4 -1
- everest/config/control_config.py +61 -2
- everest/config/control_variable_config.py +2 -1
- everest/config/everest_config.py +38 -16
- 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 +10 -10
- everest/config_file_loader.py +13 -2
- everest/detached/everserver.py +7 -8
- everest/everest_storage.py +6 -10
- everest/gui/everest_client.py +0 -1
- 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/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/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/WHEEL +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/entry_points.txt +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/licenses/COPYING +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/top_level.txt +0 -0
|
@@ -12,6 +12,7 @@ from _ert.events import (
|
|
|
12
12
|
EESnapshot,
|
|
13
13
|
EESnapshotUpdate,
|
|
14
14
|
EnsembleCancelled,
|
|
15
|
+
EnsembleEvaluationWarning,
|
|
15
16
|
EnsembleEvent,
|
|
16
17
|
EnsembleFailed,
|
|
17
18
|
EnsembleStarted,
|
|
@@ -424,7 +425,8 @@ class EnsembleSnapshot:
|
|
|
424
425
|
|
|
425
426
|
elif e_type in get_args(EnsembleEvent):
|
|
426
427
|
event = cast(EnsembleEvent, event)
|
|
427
|
-
|
|
428
|
+
if not isinstance(event, EnsembleEvaluationWarning):
|
|
429
|
+
self._ensemble_state = _ENSEMBLE_TYPE_EVENT_TO_STATUS[type(event)]
|
|
428
430
|
elif type(event) is EESnapshotUpdate:
|
|
429
431
|
self.merge_snapshot(EnsembleSnapshot.from_nested_dict(event.snapshot))
|
|
430
432
|
elif type(event) is EESnapshot:
|
ert/ensemble_evaluator/state.py
CHANGED
|
@@ -7,6 +7,7 @@ COLOR_RUNNING: Final = (255, 255, 153)
|
|
|
7
7
|
COLOR_UNKNOWN: Final = (128, 128, 128)
|
|
8
8
|
COLOR_WAITING: Final = (164, 200, 255)
|
|
9
9
|
COLOR_CANCELLED: Final = (235, 242, 246)
|
|
10
|
+
COLOR_WARNING: Final = (255, 103, 0)
|
|
10
11
|
|
|
11
12
|
ENSEMBLE_STATE_CANCELLED: Final = "Cancelled"
|
|
12
13
|
ENSEMBLE_STATE_FAILED: Final = "Failed"
|
ert/field_utils/__init__.py
CHANGED
|
@@ -4,20 +4,28 @@ from .field_file_format import FieldFileFormat
|
|
|
4
4
|
from .field_utils import (
|
|
5
5
|
ErtboxParameters,
|
|
6
6
|
Shape,
|
|
7
|
+
calc_rho_for_2d_grid_layer,
|
|
7
8
|
calculate_ertbox_parameters,
|
|
8
9
|
get_shape,
|
|
10
|
+
localization_scaling_function,
|
|
9
11
|
read_field,
|
|
10
12
|
read_mask,
|
|
11
13
|
save_field,
|
|
14
|
+
transform_local_ellipse_angle_to_local_coords,
|
|
15
|
+
transform_positions_to_local_field_coordinates,
|
|
12
16
|
)
|
|
13
17
|
|
|
14
18
|
__all__ = [
|
|
15
19
|
"ErtboxParameters",
|
|
16
20
|
"FieldFileFormat",
|
|
17
21
|
"Shape",
|
|
22
|
+
"calc_rho_for_2d_grid_layer",
|
|
18
23
|
"calculate_ertbox_parameters",
|
|
19
24
|
"get_shape",
|
|
25
|
+
"localization_scaling_function",
|
|
20
26
|
"read_field",
|
|
21
27
|
"read_mask",
|
|
22
28
|
"save_field",
|
|
29
|
+
"transform_local_ellipse_angle_to_local_coords",
|
|
30
|
+
"transform_positions_to_local_field_coordinates",
|
|
23
31
|
]
|
ert/field_utils/field_utils.py
CHANGED
|
@@ -15,7 +15,7 @@ from .roff_io import export_roff, import_roff
|
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
import numpy.typing as npt
|
|
18
|
-
import xtgeo
|
|
18
|
+
import xtgeo
|
|
19
19
|
|
|
20
20
|
_PathLike: TypeAlias = str | os.PathLike[str]
|
|
21
21
|
|
|
@@ -262,3 +262,213 @@ def save_field(
|
|
|
262
262
|
export_grdecl(field, output_path, field_name, binary=True)
|
|
263
263
|
else:
|
|
264
264
|
raise ValueError(f"Cannot export, invalid file format: {file_format}")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def transform_positions_to_local_field_coordinates(
|
|
268
|
+
coordsys_origin: tuple[float, float],
|
|
269
|
+
coordsys_rotation_angle: float,
|
|
270
|
+
utmx: npt.NDArray[np.float64],
|
|
271
|
+
utmy: npt.NDArray[np.float64],
|
|
272
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
273
|
+
"""Calculates coordinate transformation from global to local coordinates.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
coordys_origin: (x,y) coordinate of local coordinate
|
|
277
|
+
origin in global coordinates.
|
|
278
|
+
coordsys_rotation_angle: Angle for how much the local x-axis is rotated
|
|
279
|
+
anti-clockwise relative to the global x-axis in degrees.
|
|
280
|
+
utmx: vector of x-coordinates in global coordinates.
|
|
281
|
+
utmy: vector of y-coordinates in global coordinates.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
First vector is local x-coordinates and second vector is local y-coordinates.
|
|
285
|
+
"""
|
|
286
|
+
# Translate
|
|
287
|
+
x1 = utmx - coordsys_origin[0]
|
|
288
|
+
y1 = utmy - coordsys_origin[1]
|
|
289
|
+
# Rotate
|
|
290
|
+
# Input angle is the local coordinate systems rotation
|
|
291
|
+
# anticlockwise relative to global x-axis in degrees
|
|
292
|
+
rotation_of_ertbox = coordsys_rotation_angle
|
|
293
|
+
rotation_angle = np.deg2rad(rotation_of_ertbox)
|
|
294
|
+
cos_theta = np.cos(rotation_angle)
|
|
295
|
+
sin_theta = np.sin(rotation_angle)
|
|
296
|
+
x2 = x1 * cos_theta + y1 * sin_theta
|
|
297
|
+
y2 = -x1 * sin_theta + y1 * cos_theta
|
|
298
|
+
return x2, y2
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def transform_local_ellipse_angle_to_local_coords(
|
|
302
|
+
coordsys_rotation_angle: float,
|
|
303
|
+
ellipse_anisotropy_angle: npt.NDArray[np.float64],
|
|
304
|
+
) -> npt.NDArray[np.float64]:
|
|
305
|
+
"""Calculate angles relative to local coordinate system.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
coordsys_rotation_angle: Local coordinate systems rotation angle
|
|
309
|
+
relative to the global coordinate system.
|
|
310
|
+
ellipse_anisotropy_angle: Vector of input angles in global coordinates.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Vector of output angles relative to the local coordinate system.
|
|
314
|
+
"""
|
|
315
|
+
# Both angles measured anti-clock from global coordinate systems x-axis in degrees
|
|
316
|
+
return ellipse_anisotropy_angle - coordsys_rotation_angle
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def localization_scaling_function(
|
|
320
|
+
distances: npt.NDArray[np.float64],
|
|
321
|
+
) -> npt.NDArray[np.float64]:
|
|
322
|
+
"""Calculate scaling factor to be used as values in
|
|
323
|
+
RHO matrix in distance-based localization.
|
|
324
|
+
The scaling function implements the commonly
|
|
325
|
+
used function published by Gaspari and Cohn.
|
|
326
|
+
For input normalized distance >= 2, the value will be 0.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
distances: Vector of values for normalized distances.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
Values of scaling factors for each value of input distance.
|
|
333
|
+
"""
|
|
334
|
+
# "gaspari-cohn"
|
|
335
|
+
# Commonly used in distance-based localization
|
|
336
|
+
# Is exact 0 for normalized distance > 2.
|
|
337
|
+
scaling_factor = distances
|
|
338
|
+
d2 = distances**2
|
|
339
|
+
d3 = d2 * distances
|
|
340
|
+
d4 = d3 * distances
|
|
341
|
+
d5 = d4 * distances
|
|
342
|
+
s = -1 / 4 * d5 + 1 / 2 * d4 + 5 / 8 * d3 - 5 / 3 * d2 + 1
|
|
343
|
+
scaling_factor[distances <= 1] = s[distances <= 1]
|
|
344
|
+
s = (
|
|
345
|
+
1 / 12 * d5
|
|
346
|
+
- 1 / 2 * d4
|
|
347
|
+
+ 5 / 8 * d3
|
|
348
|
+
+ 5 / 3 * d2
|
|
349
|
+
- 5 * distances
|
|
350
|
+
+ 4
|
|
351
|
+
- 2 / 3 * 1 / distances
|
|
352
|
+
)
|
|
353
|
+
scaling_factor[(distances > 1) & (distances <= 2)] = s[
|
|
354
|
+
(distances > 1) & (distances <= 2)
|
|
355
|
+
]
|
|
356
|
+
scaling_factor[distances > 2] = 0.0
|
|
357
|
+
|
|
358
|
+
return scaling_factor
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def calc_rho_for_2d_grid_layer(
|
|
362
|
+
nx: int,
|
|
363
|
+
ny: int,
|
|
364
|
+
xinc: float,
|
|
365
|
+
yinc: float,
|
|
366
|
+
obs_xpos: npt.NDArray[np.float64],
|
|
367
|
+
obs_ypos: npt.NDArray[np.float64],
|
|
368
|
+
obs_main_range: npt.NDArray[np.float64],
|
|
369
|
+
obs_perp_range: npt.NDArray[np.float64],
|
|
370
|
+
obs_anisotropy_angle: npt.NDArray[np.float64],
|
|
371
|
+
right_handed_grid_indexing: bool = True,
|
|
372
|
+
) -> npt.NDArray[np.float64]:
|
|
373
|
+
"""Calculate scaling values (RHO matrix elements) for a set of observations
|
|
374
|
+
with associated localization ellipse. The method will first
|
|
375
|
+
calculate the distances from each observation position to each grid cell
|
|
376
|
+
center point of all grid cells for a 2D grid.
|
|
377
|
+
The localization method will only consider lateral distances, and it is
|
|
378
|
+
therefore sufficient to calculate the distances in 2D.
|
|
379
|
+
All input observation positions are in the local grid coordinate system
|
|
380
|
+
to simplify the calculation of the distances.
|
|
381
|
+
|
|
382
|
+
The position: xpos[n], ypos[n] and
|
|
383
|
+
localization ellipse defined by obs_main_range[n],obs_perp_range[n],
|
|
384
|
+
obs_anisotropy_angle[n]) refers to observation[n].
|
|
385
|
+
|
|
386
|
+
The distance between an observation with index n and a grid cell (i,j) is
|
|
387
|
+
d[m,n] = dist((xpos_obs[n],ypos_obs[n]),(xpos_field[i,j],ypos_field[i,j]))
|
|
388
|
+
|
|
389
|
+
RHO[[m,n] = scaling(d)
|
|
390
|
+
where m = j + i * ny for left-handed grid index origo and
|
|
391
|
+
m = (ny - j - 1) + i * ny for right-handed grid index origo
|
|
392
|
+
Note that since d[m,n] does only depend on observation index n and
|
|
393
|
+
grid cell index (i,j). The values for RHO is
|
|
394
|
+
calculated for the combination ((i,j), n) and this covers
|
|
395
|
+
one grid layer in ertbox grid or a 2D surface grid.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
nx: Number of grid cells in x-direction of local coordinate system.
|
|
399
|
+
ny: Number of grid cells in y-direction of local coordinate system.
|
|
400
|
+
xinc: Grid cell size in x-direction.
|
|
401
|
+
yinc: Grid cell size in y-direction.
|
|
402
|
+
obs_xpos: Observations x coordinates in local coordinates
|
|
403
|
+
obs_ypos: Observatiopns y coordinates in local coordinates
|
|
404
|
+
obs_main_range: Localization ellipse first range
|
|
405
|
+
obs_perp_range: Localization ellipse second range
|
|
406
|
+
obs_anisotropy_angle: Localization ellipse orientation relative
|
|
407
|
+
to local coordinate system in degrees
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
Rho matrix values for one layer of the 3D ertbox grid or for a 2D surface grid.
|
|
411
|
+
"""
|
|
412
|
+
# Center points of each grid cell in field parameter grid
|
|
413
|
+
x_local = (np.arange(nx, dtype=np.float64) + 0.5) * xinc
|
|
414
|
+
if right_handed_grid_indexing:
|
|
415
|
+
# y coordinate descreases from max to min
|
|
416
|
+
y_local = (np.arange(ny - 1, -1, -1, dtype=np.float64) + 0.5) * yinc
|
|
417
|
+
else:
|
|
418
|
+
# y coordinate increases from min to max
|
|
419
|
+
y_local = (np.arange(ny, dtype=np.float64) + 0.5) * yinc
|
|
420
|
+
mesh_x_coord, mesh_y_coord = np.meshgrid(x_local, y_local, indexing="ij")
|
|
421
|
+
|
|
422
|
+
# Number of observations
|
|
423
|
+
nobs = len(obs_xpos)
|
|
424
|
+
assert nobs == len(obs_ypos), (
|
|
425
|
+
"Number of coordinates must match number of observations"
|
|
426
|
+
)
|
|
427
|
+
assert nobs == len(obs_anisotropy_angle), (
|
|
428
|
+
"Number of ellipse orientation angles must match number of observations"
|
|
429
|
+
)
|
|
430
|
+
assert nobs == len(obs_main_range), (
|
|
431
|
+
"Number of ellipse main range values must match number of observations"
|
|
432
|
+
)
|
|
433
|
+
assert nobs == len(obs_perp_range), (
|
|
434
|
+
"Number of ellipse second range values must match number of observations"
|
|
435
|
+
)
|
|
436
|
+
assert np.all(obs_main_range > 0.0), (
|
|
437
|
+
"All range values for all observations must be positive"
|
|
438
|
+
)
|
|
439
|
+
assert np.all(obs_perp_range > 0.0), (
|
|
440
|
+
"All range values for all observations must be positive"
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
# Expand grid coordinates to match observations
|
|
444
|
+
mesh_x_coord_flat = mesh_x_coord.flatten()[:, np.newaxis] # (nx * ny, 1)
|
|
445
|
+
mesh_y_coord_flat = mesh_y_coord.flatten()[:, np.newaxis] # (nx * ny, 1)
|
|
446
|
+
|
|
447
|
+
# Observation coordinates and parameters
|
|
448
|
+
obs_xpos = obs_xpos[np.newaxis, :] # (1, nobs)
|
|
449
|
+
obs_ypos = obs_ypos[np.newaxis, :] # (1, nobs)
|
|
450
|
+
obs_main_range = obs_main_range[np.newaxis, :] # (1, nobs)
|
|
451
|
+
obs_perp_range = obs_perp_range[np.newaxis, :] # (1, nobs)
|
|
452
|
+
obs_anisotropy_angle = obs_anisotropy_angle[np.newaxis, :] # (1, nobs)
|
|
453
|
+
|
|
454
|
+
# Compute displacement between grid points and observations
|
|
455
|
+
dX = mesh_x_coord_flat - obs_xpos # (nx * ny, nobs)
|
|
456
|
+
dY = mesh_y_coord_flat - obs_ypos # (nx * ny, nobs)
|
|
457
|
+
|
|
458
|
+
# Compute rotation parameters
|
|
459
|
+
rotation = np.deg2rad(obs_anisotropy_angle)
|
|
460
|
+
cos_angle = np.cos(rotation) # (1, nobs)
|
|
461
|
+
sin_angle = np.sin(rotation) # (1, nobs)
|
|
462
|
+
|
|
463
|
+
# Rotate and scale displacements to local coordinate system defined
|
|
464
|
+
# by the two half axes of the influence ellipse. First coordinate (local x) is in
|
|
465
|
+
# direction defined by anisotropy angle and local y is perpendicular to that.
|
|
466
|
+
# Scale the distance by the ranges to get a normalized distance
|
|
467
|
+
# (with value 1 at the edge of the ellipse)
|
|
468
|
+
dX_ellipse = (dX * cos_angle + dY * sin_angle) / obs_main_range # (nx * ny, nobs)
|
|
469
|
+
dY_ellipse = (-dX * sin_angle + dY * cos_angle) / obs_perp_range # (nx * ny, nobs)
|
|
470
|
+
|
|
471
|
+
# Compute distances in the elliptical coordinate system
|
|
472
|
+
distances = np.hypot(dX_ellipse, dY_ellipse) # (nx * ny, nobs)
|
|
473
|
+
# Apply the scaling function
|
|
474
|
+
return localization_scaling_function(distances).reshape((nx, ny, nobs))
|
ert/gui/ertwidgets/__init__.py
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
2
4
|
from PyQt6.QtCore import Qt
|
|
3
5
|
from PyQt6.QtGui import QCursor
|
|
4
6
|
from PyQt6.QtWidgets import QApplication
|
|
5
|
-
from typing import Any
|
|
6
|
-
from collections.abc import Callable
|
|
7
|
-
|
|
8
7
|
|
|
9
|
-
from .closabledialog import ClosableDialog
|
|
10
8
|
from .analysismoduleedit import AnalysisModuleEdit
|
|
11
|
-
from .searchbox import SearchBox
|
|
12
|
-
from .ensembleselector import EnsembleSelector
|
|
13
9
|
from .checklist import CheckList
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
16
|
-
from .
|
|
10
|
+
from .closabledialog import ClosableDialog
|
|
11
|
+
from .copy_button import CopyButton
|
|
12
|
+
from .copyablelabel import CopyableLabel
|
|
13
|
+
from .create_experiment_dialog import CreateExperimentDialog
|
|
17
14
|
from .customdialog import CustomDialog
|
|
18
|
-
from .
|
|
15
|
+
from .ensembleselector import EnsembleSelector
|
|
16
|
+
from .listeditbox import ListEditBox
|
|
19
17
|
from .models import (
|
|
20
|
-
TextModel,
|
|
21
18
|
ActiveRealizationsModel,
|
|
19
|
+
ErtSummary,
|
|
20
|
+
PathModel,
|
|
21
|
+
SelectableListModel,
|
|
22
22
|
TargetEnsembleModel,
|
|
23
|
+
TextModel,
|
|
23
24
|
ValueModel,
|
|
24
|
-
SelectableListModel,
|
|
25
|
-
PathModel,
|
|
26
25
|
)
|
|
27
|
-
from .
|
|
28
|
-
from .
|
|
26
|
+
from .parameterviewer import get_parameters_button
|
|
27
|
+
from .pathchooser import PathChooser
|
|
28
|
+
from .searchbox import SearchBox
|
|
29
|
+
from .stringbox import StringBox
|
|
30
|
+
from .suggestor import Suggestor
|
|
31
|
+
from .textbox import TextBox
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
def showWaitCursorWhileWaiting(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
@@ -49,17 +52,21 @@ __all__ = [
|
|
|
49
52
|
"ClosableDialog",
|
|
50
53
|
"CopyButton",
|
|
51
54
|
"CopyableLabel",
|
|
55
|
+
"CreateExperimentDialog",
|
|
52
56
|
"CustomDialog",
|
|
53
57
|
"EnsembleSelector",
|
|
58
|
+
"ErtSummary",
|
|
54
59
|
"ListEditBox",
|
|
55
60
|
"PathChooser",
|
|
56
61
|
"PathModel",
|
|
57
62
|
"SearchBox",
|
|
58
63
|
"SelectableListModel",
|
|
59
64
|
"StringBox",
|
|
65
|
+
"Suggestor",
|
|
60
66
|
"TargetEnsembleModel",
|
|
61
67
|
"TextBox",
|
|
62
68
|
"TextModel",
|
|
63
69
|
"ValueModel",
|
|
70
|
+
"get_parameters_button",
|
|
64
71
|
"showWaitCursorWhileWaiting",
|
|
65
72
|
]
|
|
@@ -6,8 +6,8 @@ from PyQt6.QtCore import QMargins, Qt
|
|
|
6
6
|
from PyQt6.QtGui import QIcon
|
|
7
7
|
from PyQt6.QtWidgets import QHBoxLayout, QToolButton, QWidget
|
|
8
8
|
|
|
9
|
-
from
|
|
10
|
-
from
|
|
9
|
+
from .analysismodulevariablespanel import AnalysisModuleVariablesPanel
|
|
10
|
+
from .closabledialog import ClosableDialog
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from ert.config import AnalysisModule
|
ert/gui/ertwidgets/checklist.py
CHANGED
|
@@ -9,9 +9,11 @@ from PyQt6.QtWidgets import (
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
from ert.gui.ertnotifier import ErtNotifier
|
|
12
|
-
from ert.gui.ertwidgets import StringBox, TextModel, ValueModel
|
|
13
12
|
from ert.validation import ExperimentValidation, IntegerArgument, ProperNameArgument
|
|
14
13
|
|
|
14
|
+
from .models import TextModel, ValueModel
|
|
15
|
+
from .stringbox import StringBox
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
class CreateExperimentDialog(QDialog):
|
|
17
19
|
onDone = Signal(str, str, int)
|
|
@@ -9,11 +9,11 @@ from PyQt6.QtCore import Qt
|
|
|
9
9
|
from PyQt6.QtCore import pyqtSignal as Signal
|
|
10
10
|
from PyQt6.QtWidgets import QComboBox
|
|
11
11
|
|
|
12
|
+
from ert.config import ErrorInfo
|
|
12
13
|
from ert.gui.ertnotifier import ErtNotifier
|
|
13
14
|
from ert.storage import RealizationStorageState
|
|
14
15
|
|
|
15
|
-
from
|
|
16
|
-
from ..suggestor import Suggestor
|
|
16
|
+
from .suggestor import Suggestor
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from ert.storage import Ensemble
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .activerealizationsmodel import ActiveRealizationsModel
|
|
2
|
+
from .ertsummary import ErtSummary
|
|
2
3
|
from .path_model import PathModel
|
|
3
4
|
from .selectable_list_model import SelectableListModel
|
|
4
5
|
from .targetensemblemodel import TargetEnsembleModel
|
|
@@ -7,6 +8,7 @@ from .valuemodel import ValueModel
|
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
"ActiveRealizationsModel",
|
|
11
|
+
"ErtSummary",
|
|
10
12
|
"PathModel",
|
|
11
13
|
"SelectableListModel",
|
|
12
14
|
"TargetEnsembleModel",
|
|
@@ -2,9 +2,10 @@ from collections.abc import Collection
|
|
|
2
2
|
|
|
3
3
|
from typing_extensions import override
|
|
4
4
|
|
|
5
|
-
from ert.gui.ertwidgets.models.valuemodel import ValueModel
|
|
6
5
|
from ert.validation import ActiveRange, mask_to_rangestring
|
|
7
6
|
|
|
7
|
+
from .valuemodel import ValueModel
|
|
8
|
+
|
|
8
9
|
|
|
9
10
|
class ActiveRealizationsModel(ValueModel):
|
|
10
11
|
def __init__(self, ensemble_size: int, show_default: bool = True) -> None:
|
|
@@ -4,7 +4,8 @@ from typing_extensions import override
|
|
|
4
4
|
|
|
5
5
|
from ert.config import AnalysisConfig
|
|
6
6
|
from ert.gui.ertnotifier import ErtNotifier
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
from .valuemodel import ValueModel
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class TargetEnsembleModel(ValueModel):
|
ert/gui/ertwidgets/searchbox.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from PyQt6.QtCore import Qt
|
|
3
|
+
from PyQt6.QtCore import Qt, QTimer
|
|
4
4
|
from PyQt6.QtCore import pyqtSignal as Signal
|
|
5
5
|
from PyQt6.QtGui import QColor, QFocusEvent, QKeyEvent
|
|
6
6
|
from PyQt6.QtWidgets import QLineEdit
|
|
@@ -12,16 +12,25 @@ class SearchBox(QLineEdit):
|
|
|
12
12
|
|
|
13
13
|
filterChanged = Signal(object)
|
|
14
14
|
|
|
15
|
-
def __init__(self) -> None:
|
|
15
|
+
def __init__(self, debounce_timeout: int = 1000) -> None:
|
|
16
16
|
QLineEdit.__init__(self)
|
|
17
17
|
|
|
18
18
|
self.setToolTip("Type to search!")
|
|
19
19
|
self.active_color = self.palette().color(self.foregroundRole())
|
|
20
20
|
self.disable_search = True
|
|
21
21
|
self.presentSearch()
|
|
22
|
-
self.textChanged.connect(self.
|
|
22
|
+
self.textChanged.connect(self._start_debounce_timer)
|
|
23
|
+
self._debounce_timout = debounce_timeout
|
|
24
|
+
self._debounce_timer = QTimer(self)
|
|
25
|
+
self._debounce_timer.setSingleShot(True)
|
|
26
|
+
self._debounce_timer.timeout.connect(self._emit_filter_changed)
|
|
23
27
|
|
|
24
|
-
def
|
|
28
|
+
def _start_debounce_timer(self, _filter: Any) -> None:
|
|
29
|
+
if not self._debounce_timer.isActive():
|
|
30
|
+
self._debounce_timer.start(self._debounce_timout)
|
|
31
|
+
self._debounce_timer.setInterval(self._debounce_timout)
|
|
32
|
+
|
|
33
|
+
def _emit_filter_changed(self) -> None:
|
|
25
34
|
self.filterChanged.emit(self.filter())
|
|
26
35
|
|
|
27
36
|
def filter(self) -> str:
|
|
@@ -13,10 +13,11 @@ from PyQt6.QtWidgets import (
|
|
|
13
13
|
QVBoxLayout,
|
|
14
14
|
QWidget,
|
|
15
15
|
)
|
|
16
|
+
from typing_extensions import override
|
|
16
17
|
|
|
17
18
|
from ert.gui import is_dark_mode
|
|
18
19
|
|
|
19
|
-
from ..
|
|
20
|
+
from ..copy_button import CopyButton
|
|
20
21
|
from ._colors import (
|
|
21
22
|
BLUE_BACKGROUND,
|
|
22
23
|
BLUE_TEXT,
|
|
@@ -33,6 +34,16 @@ def _svg_icon(image_name: str) -> QSvgWidget:
|
|
|
33
34
|
return widget
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
class _CopyButton(CopyButton):
|
|
38
|
+
def __init__(self, message: str) -> None:
|
|
39
|
+
super().__init__()
|
|
40
|
+
self.message = message
|
|
41
|
+
|
|
42
|
+
@override
|
|
43
|
+
def copy(self) -> None:
|
|
44
|
+
self.copy_text(self.message)
|
|
45
|
+
|
|
46
|
+
|
|
36
47
|
class SuggestorMessage(QWidget):
|
|
37
48
|
def __init__(
|
|
38
49
|
self,
|
|
@@ -100,9 +111,7 @@ class SuggestorMessage(QWidget):
|
|
|
100
111
|
else:
|
|
101
112
|
self._expand_collapse_label = QLabel()
|
|
102
113
|
self._hbox.addWidget(self.lbl, alignment=Qt.AlignmentFlag.AlignTop)
|
|
103
|
-
self._hbox.addWidget(
|
|
104
|
-
_CopyButton(QLabel(message)), alignment=Qt.AlignmentFlag.AlignTop
|
|
105
|
-
)
|
|
114
|
+
self._hbox.addWidget(_CopyButton(message), alignment=Qt.AlignmentFlag.AlignTop)
|
|
106
115
|
|
|
107
116
|
def _toggle_expand(self, _link: Any) -> None:
|
|
108
117
|
if self._expanded:
|
ert/gui/main.py
CHANGED
|
@@ -8,6 +8,7 @@ import traceback
|
|
|
8
8
|
import types
|
|
9
9
|
from collections import Counter
|
|
10
10
|
from importlib.resources import files
|
|
11
|
+
from pathlib import Path
|
|
11
12
|
from signal import SIG_DFL, SIGINT, signal
|
|
12
13
|
|
|
13
14
|
from opentelemetry.trace import Status, StatusCode
|
|
@@ -27,11 +28,16 @@ from ert.gui.tools.event_viewer import (
|
|
|
27
28
|
)
|
|
28
29
|
from ert.namespace import Namespace
|
|
29
30
|
from ert.plugins import ErtRuntimePlugins, get_site_plugins
|
|
30
|
-
from ert.services import
|
|
31
|
-
from ert.storage import
|
|
31
|
+
from ert.services import ErtServer
|
|
32
|
+
from ert.storage import (
|
|
33
|
+
ErtStorageException,
|
|
34
|
+
LocalStorage,
|
|
35
|
+
local_storage_set_ert_config,
|
|
36
|
+
open_storage,
|
|
37
|
+
)
|
|
32
38
|
from ert.trace import trace, tracer
|
|
33
39
|
|
|
34
|
-
from .
|
|
40
|
+
from .ertwidgets import Suggestor
|
|
35
41
|
|
|
36
42
|
logger = logging.getLogger(__name__)
|
|
37
43
|
|
|
@@ -113,7 +119,7 @@ def run_gui(args: Namespace, plugins: ErtRuntimePlugins | None = None) -> int:
|
|
|
113
119
|
return show_window()
|
|
114
120
|
|
|
115
121
|
try:
|
|
116
|
-
with
|
|
122
|
+
with ErtServer.init_service(project=Path(ens_path).absolute()):
|
|
117
123
|
return show_window()
|
|
118
124
|
except PermissionError as pe:
|
|
119
125
|
print(f"Error: {pe}", file=sys.stderr)
|
|
@@ -157,9 +163,10 @@ def _start_initial_gui_window(
|
|
|
157
163
|
storage_path = None
|
|
158
164
|
if ert_config is not None:
|
|
159
165
|
try:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
if LocalStorage.check_migration_needed(Path(ert_config.ens_path)):
|
|
167
|
+
# Open in write mode to initialize the storage, so that
|
|
168
|
+
# dark storage can be mounted onto it
|
|
169
|
+
open_storage(ert_config.ens_path, mode="w").close()
|
|
163
170
|
storage_path = ert_config.ens_path
|
|
164
171
|
except ErtStorageException as err:
|
|
165
172
|
validation_messages.errors.append(
|
ert/gui/main_window.py
CHANGED
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
from PyQt6.QtCore import QCoreApplication, QEvent, QSize, Qt
|
|
10
10
|
from PyQt6.QtCore import pyqtSignal as Signal
|
|
11
11
|
from PyQt6.QtCore import pyqtSlot as Slot
|
|
12
|
-
from PyQt6.QtGui import QAction, QCloseEvent, QCursor,
|
|
12
|
+
from PyQt6.QtGui import QAction, QCloseEvent, QCursor, QIcon, QMouseEvent
|
|
13
13
|
from PyQt6.QtWidgets import (
|
|
14
14
|
QButtonGroup,
|
|
15
15
|
QFrame,
|
|
@@ -96,7 +96,6 @@ class ErtMainWindow(QMainWindow):
|
|
|
96
96
|
log_handler: GUILogHandler | None = None,
|
|
97
97
|
) -> None:
|
|
98
98
|
QMainWindow.__init__(self)
|
|
99
|
-
self.available_fonts = QFontDatabase.families()
|
|
100
99
|
self.notifier = ErtNotifier()
|
|
101
100
|
self.plugins_tool: PluginsTool | None = None
|
|
102
101
|
self.ert_config = ert_config
|
|
@@ -17,6 +17,7 @@ from ert.gui.ertwidgets import (
|
|
|
17
17
|
CopyableLabel,
|
|
18
18
|
StringBox,
|
|
19
19
|
TextModel,
|
|
20
|
+
get_parameters_button,
|
|
20
21
|
)
|
|
21
22
|
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
|
|
22
23
|
from ert.run_models import EnsembleExperiment
|
|
@@ -24,7 +25,6 @@ from ert.validation import ExperimentValidation, ProperNameArgument
|
|
|
24
25
|
from ert.validation.active_range import ActiveRange
|
|
25
26
|
from ert.validation.range_string_argument import RangeSubsetStringArgument
|
|
26
27
|
|
|
27
|
-
from ..ertwidgets.parameterviewer import get_parameters_button
|
|
28
28
|
from ._design_matrix_panel import DesignMatrixPanel
|
|
29
29
|
from .experiment_config_panel import ExperimentConfigPanel
|
|
30
30
|
|
|
@@ -14,6 +14,7 @@ from ert.gui.ertwidgets import (
|
|
|
14
14
|
StringBox,
|
|
15
15
|
TargetEnsembleModel,
|
|
16
16
|
TextModel,
|
|
17
|
+
get_parameters_button,
|
|
17
18
|
)
|
|
18
19
|
from ert.mode_definitions import ENIF_MODE
|
|
19
20
|
from ert.run_models import EnsembleInformationFilter
|
|
@@ -24,7 +25,6 @@ from ert.validation import (
|
|
|
24
25
|
from ert.validation.active_range import ActiveRange
|
|
25
26
|
from ert.validation.range_string_argument import RangeSubsetStringArgument
|
|
26
27
|
|
|
27
|
-
from ..ertwidgets.parameterviewer import get_parameters_button
|
|
28
28
|
from ._design_matrix_panel import DesignMatrixPanel
|
|
29
29
|
from .experiment_config_panel import ExperimentConfigPanel
|
|
30
30
|
|
|
@@ -16,6 +16,7 @@ from ert.gui.ertwidgets import (
|
|
|
16
16
|
StringBox,
|
|
17
17
|
TargetEnsembleModel,
|
|
18
18
|
TextModel,
|
|
19
|
+
get_parameters_button,
|
|
19
20
|
)
|
|
20
21
|
from ert.mode_definitions import ENSEMBLE_SMOOTHER_MODE
|
|
21
22
|
from ert.run_models import EnsembleSmoother
|
|
@@ -26,7 +27,6 @@ from ert.validation import (
|
|
|
26
27
|
from ert.validation.active_range import ActiveRange
|
|
27
28
|
from ert.validation.range_string_argument import RangeSubsetStringArgument
|
|
28
29
|
|
|
29
|
-
from ..ertwidgets.parameterviewer import get_parameters_button
|
|
30
30
|
from ._design_matrix_panel import DesignMatrixPanel
|
|
31
31
|
from .experiment_config_panel import ExperimentConfigPanel
|
|
32
32
|
|
|
@@ -14,9 +14,9 @@ from ert.gui.ertwidgets import (
|
|
|
14
14
|
CopyableLabel,
|
|
15
15
|
EnsembleSelector,
|
|
16
16
|
StringBox,
|
|
17
|
+
Suggestor,
|
|
17
18
|
)
|
|
18
19
|
from ert.gui.simulation.experiment_config_panel import ExperimentConfigPanel
|
|
19
|
-
from ert.gui.suggestor import Suggestor
|
|
20
20
|
from ert.mode_definitions import EVALUATE_ENSEMBLE_MODE
|
|
21
21
|
from ert.run_models.evaluate_ensemble import EvaluateEnsemble
|
|
22
22
|
from ert.storage import RealizationStorageState
|
|
@@ -364,7 +364,7 @@ class ExperimentPanel(QWidget):
|
|
|
364
364
|
run_path=Path(self.config.runpath_config.runpath_format_string),
|
|
365
365
|
storage_path=self._notifier.storage.path,
|
|
366
366
|
)
|
|
367
|
-
self._dialog.set_queue_system_name(model.queue_system)
|
|
367
|
+
self._dialog.set_queue_system_name(model.queue_config.queue_system)
|
|
368
368
|
self.experiment_started.emit(self._dialog)
|
|
369
369
|
self._simulation_done = False
|
|
370
370
|
self.run_button.setEnabled(self._simulation_done)
|