ert 16.0.9__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/forward_model_runner/fm_dispatch.py +9 -6
- _ert/forward_model_runner/reporting/event.py +1 -0
- _ert/forward_model_runner/runner.py +1 -2
- _ert/utils.py +12 -0
- ert/__main__.py +58 -38
- ert/analysis/_enif_update.py +8 -4
- ert/analysis/_es_update.py +19 -6
- ert/analysis/_update_commons.py +16 -6
- ert/base_model_context.py +1 -1
- ert/cli/main.py +17 -12
- ert/cli/monitor.py +7 -0
- ert/config/__init__.py +17 -6
- ert/config/_create_observation_dataframes.py +118 -21
- ert/config/_get_num_cpu.py +1 -1
- ert/config/_observations.py +91 -2
- ert/config/_read_summary.py +74 -328
- ert/config/design_matrix.py +62 -23
- ert/config/distribution.py +1 -1
- ert/config/ensemble_config.py +9 -17
- ert/config/ert_config.py +155 -58
- ert/config/everest_control.py +234 -0
- ert/config/{everest_constraints_config.py → everest_response.py} +27 -15
- ert/config/field.py +99 -90
- ert/config/forward_model_step.py +122 -17
- ert/config/gen_data_config.py +5 -10
- ert/config/gen_kw_config.py +11 -41
- 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_errors.py +1 -1
- ert/config/parsing/config_keywords.py +2 -1
- ert/config/parsing/config_schema.py +23 -11
- ert/config/parsing/config_schema_deprecations.py +3 -3
- 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 +42 -50
- 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 +73 -26
- ert/config/workflow_fixtures.py +2 -1
- ert/config/workflow_job.py +135 -54
- 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 +12 -3
- ert/dark_storage/compute/misfits.py +11 -7
- ert/dark_storage/endpoints/compute/misfits.py +6 -4
- ert/dark_storage/endpoints/ensembles.py +4 -0
- ert/dark_storage/endpoints/experiment_server.py +30 -24
- ert/dark_storage/endpoints/experiments.py +2 -2
- ert/dark_storage/endpoints/observations.py +8 -6
- ert/dark_storage/endpoints/parameters.py +4 -12
- ert/dark_storage/endpoints/responses.py +24 -5
- ert/dark_storage/json_schema/ensemble.py +3 -0
- 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 +228 -15
- ert/field_utils/grdecl_io.py +1 -1
- 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/closabledialog.py +2 -0
- ert/gui/ertwidgets/copyablelabel.py +2 -0
- ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
- ert/gui/ertwidgets/ensembleselector.py +2 -2
- ert/gui/ertwidgets/listeditbox.py +2 -0
- ert/gui/ertwidgets/models/__init__.py +2 -0
- ert/gui/ertwidgets/models/activerealizationsmodel.py +5 -1
- ert/gui/ertwidgets/models/path_model.py +1 -1
- ert/gui/ertwidgets/models/targetensemblemodel.py +5 -1
- ert/gui/ertwidgets/models/text_model.py +4 -1
- ert/gui/ertwidgets/pathchooser.py +0 -3
- ert/gui/ertwidgets/searchbox.py +17 -4
- ert/gui/ertwidgets/stringbox.py +2 -0
- ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +63 -30
- ert/gui/main.py +41 -13
- ert/gui/main_window.py +3 -7
- ert/gui/model/fm_step_list.py +3 -0
- ert/gui/model/real_list.py +1 -0
- ert/gui/model/snapshot.py +1 -0
- ert/gui/simulation/combobox_with_description.py +3 -0
- ert/gui/simulation/ensemble_experiment_panel.py +8 -2
- ert/gui/simulation/ensemble_information_filter_panel.py +7 -2
- ert/gui/simulation/ensemble_smoother_panel.py +8 -2
- ert/gui/simulation/evaluate_ensemble_panel.py +17 -7
- ert/gui/simulation/experiment_panel.py +18 -6
- ert/gui/simulation/manual_update_panel.py +35 -10
- ert/gui/simulation/multiple_data_assimilation_panel.py +13 -9
- ert/gui/simulation/run_dialog.py +47 -20
- ert/gui/simulation/single_test_run_panel.py +6 -3
- ert/gui/simulation/view/progress_widget.py +2 -0
- ert/gui/simulation/view/realization.py +5 -1
- ert/gui/simulation/view/update.py +2 -0
- ert/gui/summarypanel.py +20 -1
- ert/gui/tools/event_viewer/panel.py +3 -4
- ert/gui/tools/event_viewer/tool.py +2 -0
- ert/gui/tools/load_results/load_results_panel.py +1 -1
- ert/gui/tools/load_results/load_results_tool.py +2 -0
- ert/gui/tools/manage_experiments/export_dialog.py +136 -0
- ert/gui/tools/manage_experiments/manage_experiments_panel.py +2 -0
- ert/gui/tools/manage_experiments/storage_info_widget.py +121 -16
- ert/gui/tools/manage_experiments/storage_widget.py +4 -3
- ert/gui/tools/plot/customize/color_chooser.py +5 -2
- ert/gui/tools/plot/customize/customize_plot_dialog.py +2 -0
- ert/gui/tools/plot/customize/default_customization_view.py +4 -0
- ert/gui/tools/plot/customize/limits_customization_view.py +3 -0
- ert/gui/tools/plot/customize/statistics_customization_view.py +3 -0
- ert/gui/tools/plot/customize/style_chooser.py +2 -0
- ert/gui/tools/plot/customize/style_customization_view.py +3 -0
- ert/gui/tools/plot/data_type_keys_widget.py +2 -0
- ert/gui/tools/plot/data_type_proxy_model.py +3 -0
- ert/gui/tools/plot/plot_api.py +50 -28
- ert/gui/tools/plot/plot_ensemble_selection_widget.py +17 -10
- ert/gui/tools/plot/plot_widget.py +15 -2
- ert/gui/tools/plot/plot_window.py +41 -19
- 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 +13 -5
- 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/gui/tools/plot/widgets/clearable_line_edit.py +9 -0
- ert/gui/tools/plot/widgets/filter_popup.py +2 -0
- ert/gui/tools/plot/widgets/filterable_kw_list_model.py +3 -0
- ert/gui/tools/plugins/plugin.py +1 -1
- ert/gui/tools/plugins/plugins_tool.py +2 -0
- ert/gui/tools/plugins/process_job_dialog.py +3 -0
- ert/gui/tools/workflows/workflow_dialog.py +2 -0
- ert/gui/tools/workflows/workflows_tool.py +2 -0
- ert/libres_facade.py +5 -7
- ert/logging/__init__.py +4 -1
- ert/mode_definitions.py +2 -0
- ert/plugins/__init__.py +4 -6
- 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 -10
- ert/plugins/hook_specifications/jobs.py +0 -9
- ert/plugins/plugin_manager.py +53 -124
- ert/resources/forward_models/run_reservoirsimulator.py +8 -4
- ert/resources/forward_models/template_render.py +10 -10
- ert/resources/shell_scripts/delete_directory.py +2 -2
- ert/run_models/__init__.py +24 -6
- ert/run_models/_create_run_path.py +133 -38
- 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 +337 -113
- 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 +78 -18
- ert/run_models/multiple_data_assimilation.py +22 -11
- ert/run_models/run_model.py +72 -73
- 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/__init__.py +10 -5
- ert/scheduler/driver.py +40 -0
- ert/scheduler/event.py +3 -1
- ert/scheduler/job.py +23 -13
- ert/scheduler/lsf_driver.py +15 -5
- ert/scheduler/openpbs_driver.py +10 -4
- ert/scheduler/scheduler.py +5 -0
- ert/scheduler/slurm_driver.py +20 -5
- ert/services/__init__.py +2 -2
- ert/services/_base_service.py +37 -20
- ert/services/_storage_main.py +20 -18
- 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 +14 -1
- ert/storage/local_ensemble.py +44 -13
- ert/storage/local_experiment.py +54 -34
- ert/storage/local_storage.py +90 -58
- ert/storage/migration/to10.py +3 -2
- ert/storage/migration/to11.py +9 -10
- ert/storage/migration/to12.py +19 -20
- ert/storage/migration/to13.py +28 -27
- ert/storage/migration/to14.py +3 -3
- ert/storage/migration/to15.py +25 -0
- 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/to6.py +3 -2
- ert/storage/migration/to7.py +12 -13
- ert/storage/migration/to8.py +9 -11
- ert/storage/migration/to9.py +5 -4
- ert/storage/realization_storage_state.py +7 -7
- ert/substitutions.py +12 -28
- ert/validation/active_range.py +7 -7
- ert/validation/ensemble_realizations_argument.py +4 -2
- ert/validation/rangestring.py +16 -16
- ert/workflow_runner.py +6 -3
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/METADATA +21 -15
- ert-19.0.0rc2.dist-info/RECORD +524 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/WHEEL +1 -1
- everest/api/everest_data_api.py +14 -1
- everest/assets/everest_logo.svg +406 -0
- everest/bin/config_branch_script.py +30 -14
- everest/bin/everconfigdump_script.py +2 -10
- everest/bin/everest_script.py +53 -33
- everest/bin/everlint_script.py +3 -5
- everest/bin/kill_script.py +7 -5
- everest/bin/main.py +11 -24
- everest/bin/monitor_script.py +64 -35
- everest/bin/utils.py +58 -43
- everest/bin/visualization_script.py +23 -13
- 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 +102 -79
- everest/config/forward_model_config.py +5 -3
- everest/config/install_data_config.py +7 -5
- everest/config/install_job_config.py +45 -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 -55
- everest/config/simulator_config.py +62 -17
- everest/config/utils.py +25 -105
- everest/config/validation_utils.py +34 -15
- everest/config_file_loader.py +30 -21
- everest/detached/__init__.py +0 -6
- everest/detached/client.py +7 -52
- everest/detached/everserver.py +19 -45
- everest/everest_storage.py +24 -40
- everest/gui/everest_client.py +2 -3
- everest/gui/main_window.py +2 -2
- everest/optimizer/everest2ropt.py +68 -42
- everest/optimizer/opt_model_transforms.py +15 -20
- everest/optimizer/utils.py +0 -29
- everest/plugins/hook_specs.py +0 -24
- everest/strings.py +1 -6
- everest/util/__init__.py +3 -1
- ert/config/everest_objective_config.py +0 -95
- ert/config/ext_param_config.py +0 -107
- 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 -67
- ert/gui/tools/export/exporter.py +0 -36
- ert/plugins/hook_specifications/ecl_config.py +0 -29
- ert/services/storage_service.py +0 -127
- ert/summary_key_type.py +0 -234
- ert-16.0.9.dist-info/RECORD +0 -521
- everest/bin/everexport_script.py +0 -53
- everest/config/sampler_config.py +0 -103
- everest/simulator/__init__.py +0 -88
- everest/simulator/everest_to_ert.py +0 -252
- /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
- /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/entry_points.txt +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/licenses/COPYING +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/top_level.txt +0 -0
everest/config/server_config.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import os
|
|
3
|
-
from pathlib import Path
|
|
4
2
|
from textwrap import dedent
|
|
5
3
|
from typing import Any
|
|
6
4
|
|
|
@@ -12,15 +10,9 @@ from ert.config.queue_config import (
|
|
|
12
10
|
SlurmQueueOptions,
|
|
13
11
|
TorqueQueueOptions,
|
|
14
12
|
)
|
|
15
|
-
from ert.dark_storage.client import
|
|
13
|
+
from ert.dark_storage.client import ErtClientConnectionInfo
|
|
16
14
|
|
|
17
|
-
from ..strings import
|
|
18
|
-
CERTIFICATE_DIR,
|
|
19
|
-
DETACHED_NODE_DIR,
|
|
20
|
-
HOSTFILE_NAME,
|
|
21
|
-
SERVER_STATUS,
|
|
22
|
-
SESSION_DIR,
|
|
23
|
-
)
|
|
15
|
+
from ..strings import SESSION_DIR
|
|
24
16
|
from .simulator_config import check_removed_config
|
|
25
17
|
|
|
26
18
|
|
|
@@ -60,21 +52,11 @@ class ServerConfig(BaseModel):
|
|
|
60
52
|
check_removed_config(data.get("queue_system"))
|
|
61
53
|
return data
|
|
62
54
|
|
|
63
|
-
@staticmethod
|
|
64
|
-
def get_server_url(output_dir: str) -> str:
|
|
65
|
-
"""Return the url of the server.
|
|
66
|
-
|
|
67
|
-
If server_info are given, the url is generated using that info. Otherwise
|
|
68
|
-
server information are retrieved from the hostfile
|
|
69
|
-
"""
|
|
70
|
-
server_info = ServerConfig.get_server_info(output_dir)
|
|
71
|
-
return f"https://{server_info['host']}:{server_info['port']}/experiment_server"
|
|
72
|
-
|
|
73
55
|
@staticmethod
|
|
74
56
|
def get_server_context_from_conn_info(
|
|
75
|
-
conn_info:
|
|
57
|
+
conn_info: ErtClientConnectionInfo,
|
|
76
58
|
) -> tuple[str, str, tuple[str, str]]:
|
|
77
|
-
"""Get server connection context information from a
|
|
59
|
+
"""Get server connection context information from a ErtClientConnectionInfo.
|
|
78
60
|
|
|
79
61
|
Returns a tuple containing the server URL, certificate file path,
|
|
80
62
|
and authentication credentials.
|
|
@@ -84,7 +66,7 @@ class ServerConfig(BaseModel):
|
|
|
84
66
|
This should be refactored to use the ERT Storage Client class directly instead.
|
|
85
67
|
|
|
86
68
|
Args:
|
|
87
|
-
conn_info: An instance of the
|
|
69
|
+
conn_info: An instance of the ErtClientConnectionInfo
|
|
88
70
|
|
|
89
71
|
Returns:
|
|
90
72
|
tuple: A tuple containing:
|
|
@@ -103,39 +85,8 @@ class ServerConfig(BaseModel):
|
|
|
103
85
|
|
|
104
86
|
return url, cert_file, auth
|
|
105
87
|
|
|
106
|
-
@staticmethod
|
|
107
|
-
def get_server_info(output_dir: str) -> dict[str, Any]:
|
|
108
|
-
"""Load server information from the hostfile"""
|
|
109
|
-
host_file_path = Path(ServerConfig.get_hostfile_path(output_dir))
|
|
110
|
-
if not host_file_path.exists():
|
|
111
|
-
return {"host": None, "port": None, "cert": None, "auth": None}
|
|
112
|
-
|
|
113
|
-
data = json.loads(host_file_path.read_text(encoding="utf-8"))
|
|
114
|
-
|
|
115
|
-
if not all(k in data for k in ("host", "port", "cert", "auth")):
|
|
116
|
-
raise RuntimeError("Malformed hostfile")
|
|
117
|
-
return data
|
|
118
|
-
|
|
119
|
-
@staticmethod
|
|
120
|
-
def get_detached_node_dir(output_dir: str) -> str:
|
|
121
|
-
return os.path.join(os.path.abspath(output_dir), DETACHED_NODE_DIR)
|
|
122
|
-
|
|
123
|
-
@staticmethod
|
|
124
|
-
def get_hostfile_path(output_dir: str) -> str:
|
|
125
|
-
return os.path.join(ServerConfig.get_session_dir(output_dir), HOSTFILE_NAME)
|
|
126
|
-
|
|
127
88
|
@staticmethod
|
|
128
89
|
def get_session_dir(output_dir: str) -> str:
|
|
129
90
|
"""Return path to the session directory containing information about the
|
|
130
91
|
certificates and host information"""
|
|
131
|
-
return os.path.join(
|
|
132
|
-
|
|
133
|
-
@staticmethod
|
|
134
|
-
def get_everserver_status_path(output_dir: str) -> str:
|
|
135
|
-
"""Returns path to the everest server status file"""
|
|
136
|
-
return os.path.join(ServerConfig.get_session_dir(output_dir), SERVER_STATUS)
|
|
137
|
-
|
|
138
|
-
@staticmethod
|
|
139
|
-
def get_certificate_dir(output_dir: str) -> str:
|
|
140
|
-
"""Return the path to certificate folder"""
|
|
141
|
-
return os.path.join(ServerConfig.get_session_dir(output_dir), CERTIFICATE_DIR)
|
|
92
|
+
return os.path.join(os.path.abspath(output_dir), SESSION_DIR)
|
|
@@ -75,9 +75,22 @@ class SimulatorConfig(BaseModelWithContextSupport, extra="forbid"):
|
|
|
75
75
|
default=None,
|
|
76
76
|
description=dedent(
|
|
77
77
|
"""
|
|
78
|
-
|
|
78
|
+
Amount of memory to set aside for a forward model.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
This information is propagated to the queue system as the amount of memory
|
|
81
|
+
to reserve/book for a realization to complete. It is up to the configuration
|
|
82
|
+
of the queuing system how to treat this information, but usually it will
|
|
83
|
+
stop more realizations being assigned to a compute node if the compute nodes
|
|
84
|
+
memory is already fully booked.
|
|
85
|
+
|
|
86
|
+
Setting this number lower than the peak memory consumption of each
|
|
87
|
+
realization puts the realization at risk of being killed in an out-of-memory
|
|
88
|
+
situation. Setting this number higher than needed will give longer wait
|
|
89
|
+
times in the queue.
|
|
90
|
+
|
|
91
|
+
For the local queue system, this keyword has no effect. In that scenario,
|
|
92
|
+
you can use `max_running` to choke the memory consumption.
|
|
93
|
+
scheduling of compute jobs.
|
|
81
94
|
|
|
82
95
|
`max_memory` may be an integer value, indicating the number of
|
|
83
96
|
bytes, or a string consisting of a number followed by a unit. The
|
|
@@ -94,9 +107,6 @@ class SimulatorConfig(BaseModelWithContextSupport, extra="forbid"):
|
|
|
94
107
|
Spaces between the number and the unit are ignored, and so are any
|
|
95
108
|
characters after the first. For example: 2g, 2G, and 2 GB all
|
|
96
109
|
resolve to the same value: 2 gigabytes, equaling 2 * 1024**3 bytes.
|
|
97
|
-
|
|
98
|
-
If not set, or a set to zero, the allowed amount of memory is
|
|
99
|
-
unlimited.
|
|
100
110
|
"""
|
|
101
111
|
),
|
|
102
112
|
)
|
|
@@ -132,17 +142,40 @@ class SimulatorConfig(BaseModelWithContextSupport, extra="forbid"):
|
|
|
132
142
|
),
|
|
133
143
|
)
|
|
134
144
|
|
|
135
|
-
@
|
|
145
|
+
@model_validator(mode="before")
|
|
136
146
|
@classmethod
|
|
137
|
-
def
|
|
138
|
-
|
|
147
|
+
def apply_site_or_default_queue_if_no_user_queue(
|
|
148
|
+
cls, data: dict[str, Any], info: ValidationInfo
|
|
149
|
+
) -> Any:
|
|
150
|
+
queue_system = data.get("queue_system")
|
|
151
|
+
if queue_system is None:
|
|
139
152
|
options = None
|
|
140
153
|
if info.context:
|
|
141
154
|
options = info.context.queue_options
|
|
142
|
-
return options or LocalQueueOptions(max_running=8)
|
|
143
|
-
return v
|
|
144
155
|
|
|
145
|
-
|
|
156
|
+
defaulted_queue_options = (
|
|
157
|
+
options.model_dump()
|
|
158
|
+
if options is not None
|
|
159
|
+
else LocalQueueOptions(max_running=8).model_dump()
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
user_configured_max_memory = data.get("max_memory")
|
|
163
|
+
if user_configured_max_memory is not None:
|
|
164
|
+
cls.validate_max_memory(max_memory=user_configured_max_memory)
|
|
165
|
+
defaulted_queue_options["realization_memory"] = (
|
|
166
|
+
user_configured_max_memory
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
user_configured_cores_per_node = data.get("cores_per_node")
|
|
170
|
+
if user_configured_cores_per_node is not None:
|
|
171
|
+
defaulted_queue_options["num_cpu"] = user_configured_cores_per_node
|
|
172
|
+
|
|
173
|
+
data["queue_system"] = defaulted_queue_options
|
|
174
|
+
data["max_memory"] = None
|
|
175
|
+
|
|
176
|
+
return data
|
|
177
|
+
|
|
178
|
+
@field_validator("max_memory", mode="before")
|
|
146
179
|
@classmethod
|
|
147
180
|
def validate_max_memory(cls, max_memory: int | str | None) -> str | None:
|
|
148
181
|
if max_memory is None:
|
|
@@ -163,14 +196,26 @@ class SimulatorConfig(BaseModelWithContextSupport, extra="forbid"):
|
|
|
163
196
|
|
|
164
197
|
@model_validator(mode="after")
|
|
165
198
|
def update_max_memory(config: "SimulatorConfig") -> "SimulatorConfig":
|
|
199
|
+
if config.max_memory is None:
|
|
200
|
+
return config
|
|
201
|
+
parsed_max_memory = (
|
|
202
|
+
parse_string_to_bytes(config.max_memory)
|
|
203
|
+
if type(config.max_memory) is str
|
|
204
|
+
else int(config.max_memory)
|
|
205
|
+
)
|
|
166
206
|
if (
|
|
167
|
-
config.
|
|
168
|
-
and config.queue_system is not None
|
|
207
|
+
config.queue_system is not None
|
|
169
208
|
and config.queue_system.realization_memory == 0
|
|
170
209
|
):
|
|
171
|
-
config.queue_system.realization_memory =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
210
|
+
config.queue_system.realization_memory = parsed_max_memory
|
|
211
|
+
elif (
|
|
212
|
+
config.queue_system is not None
|
|
213
|
+
and config.queue_system.realization_memory > 0
|
|
214
|
+
and config.queue_system.realization_memory != parsed_max_memory
|
|
215
|
+
):
|
|
216
|
+
raise ConfigValidationError(
|
|
217
|
+
"Ambiguous configuration of realization_memory. "
|
|
218
|
+
"Specify either max_memory or realization_memory, not both"
|
|
175
219
|
)
|
|
220
|
+
|
|
176
221
|
return config
|
everest/config/utils.py
CHANGED
|
@@ -1,108 +1,28 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Any, Literal
|
|
1
|
+
from ert.config import EverestControl, SamplerConfig
|
|
3
2
|
|
|
4
|
-
from .control_config import ControlConfig
|
|
5
|
-
from .control_variable_config import ControlVariableGuessListConfig
|
|
6
|
-
from .sampler_config import SamplerConfig
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def __init__(self, controls: list[ControlConfig]) -> None:
|
|
11
|
-
control_dicts = _get_control_dicts(controls)
|
|
12
|
-
self.names = [control["name"] for control in control_dicts]
|
|
13
|
-
self.types: list[Literal["real", "integer"]] = [
|
|
14
|
-
control["control_type"] for control in control_dicts
|
|
15
|
-
]
|
|
16
|
-
self.initial_guesses = [control["initial_guess"] for control in control_dicts]
|
|
17
|
-
self.lower_bounds = [control["min"] for control in control_dicts]
|
|
18
|
-
self.upper_bounds = [control["max"] for control in control_dicts]
|
|
19
|
-
self.scaled_ranges = [control["scaled_range"] for control in control_dicts]
|
|
20
|
-
self.enabled = [control["enabled"] for control in control_dicts]
|
|
21
|
-
self.perturbation_magnitudes = [
|
|
22
|
-
control["perturbation_magnitude"] for control in control_dicts
|
|
23
|
-
]
|
|
24
|
-
self.perturbation_types = [
|
|
25
|
-
control["perturbation_type"] for control in control_dicts
|
|
26
|
-
]
|
|
27
|
-
self.samplers, self.sampler_indices = _get_samplers(controls)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def _get_control_dicts(controls: list[ControlConfig]) -> list[dict[str, Any]]:
|
|
31
|
-
def _inject_defaults(control: ControlConfig, var_dict: dict[str, Any]) -> None:
|
|
32
|
-
for key in [
|
|
33
|
-
"type",
|
|
34
|
-
"initial_guess",
|
|
35
|
-
"control_type",
|
|
36
|
-
"enabled",
|
|
37
|
-
"min",
|
|
38
|
-
"max",
|
|
39
|
-
"perturbation_type",
|
|
40
|
-
"perturbation_magnitude",
|
|
41
|
-
"scaled_range",
|
|
42
|
-
]:
|
|
43
|
-
if var_dict.get(key) is None:
|
|
44
|
-
var_dict[key] = getattr(control, key)
|
|
45
|
-
|
|
46
|
-
control_dicts: list[dict[str, Any]] = []
|
|
47
|
-
for control in controls:
|
|
48
|
-
for variable in control.variables:
|
|
49
|
-
if isinstance(variable, ControlVariableGuessListConfig):
|
|
50
|
-
for index, guess in enumerate(variable.initial_guess, start=1):
|
|
51
|
-
var_dict = deepcopy(variable.model_dump())
|
|
52
|
-
var_dict["name"] = (control.name, variable.name, index)
|
|
53
|
-
var_dict["initial_guess"] = guess
|
|
54
|
-
_inject_defaults(control, var_dict)
|
|
55
|
-
control_dicts.append(var_dict)
|
|
56
|
-
else:
|
|
57
|
-
var_dict = deepcopy(variable.model_dump())
|
|
58
|
-
var_dict["name"] = (
|
|
59
|
-
(control.name, variable.name)
|
|
60
|
-
if variable.index is None
|
|
61
|
-
else (control.name, variable.name, variable.index)
|
|
62
|
-
)
|
|
63
|
-
_inject_defaults(control, var_dict)
|
|
64
|
-
control_dicts.append(var_dict)
|
|
65
|
-
return control_dicts
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _get_samplers(
|
|
69
|
-
controls: list[ControlConfig],
|
|
4
|
+
def get_samplers(
|
|
5
|
+
controls: list[EverestControl],
|
|
70
6
|
) -> tuple[list[SamplerConfig | None], list[int]]:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
samplers.append(None)
|
|
94
|
-
default_sampler_index = len(samplers) - 1
|
|
95
|
-
variable_sampler_index = default_sampler_index
|
|
96
|
-
|
|
97
|
-
if isinstance(variable, ControlVariableGuessListConfig):
|
|
98
|
-
sampler_indices.extend(
|
|
99
|
-
[variable_sampler_index] * len(variable.initial_guess)
|
|
100
|
-
)
|
|
101
|
-
else:
|
|
102
|
-
sampler_indices.append(variable_sampler_index)
|
|
103
|
-
|
|
104
|
-
return samplers, sampler_indices
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def flatten_controls(controls: list[ControlConfig]) -> FlattenedControls:
|
|
108
|
-
return FlattenedControls(controls)
|
|
7
|
+
"""
|
|
8
|
+
Create a list of unique samplers, and a list mapping variable index
|
|
9
|
+
to sampler index. I.e., this points each control variable to
|
|
10
|
+
a sampler by index.
|
|
11
|
+
"""
|
|
12
|
+
flattened_samplers = [
|
|
13
|
+
sampler for control in controls for sampler in control.samplers
|
|
14
|
+
]
|
|
15
|
+
unique_samplers: list[SamplerConfig | None] = []
|
|
16
|
+
variable_to_unique_sampler_index: list[int] = []
|
|
17
|
+
for sampler in flattened_samplers:
|
|
18
|
+
try:
|
|
19
|
+
unique_sampler_index = next(
|
|
20
|
+
i for i, s in enumerate(unique_samplers) if s == sampler
|
|
21
|
+
)
|
|
22
|
+
except StopIteration:
|
|
23
|
+
unique_sampler_index = len(unique_samplers)
|
|
24
|
+
unique_samplers.append(sampler)
|
|
25
|
+
|
|
26
|
+
variable_to_unique_sampler_index.append(unique_sampler_index)
|
|
27
|
+
|
|
28
|
+
return unique_samplers, variable_to_unique_sampler_index
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import errno
|
|
2
2
|
import os
|
|
3
3
|
import tempfile
|
|
4
|
+
import types
|
|
4
5
|
from collections import Counter
|
|
5
6
|
from collections.abc import Sequence
|
|
6
7
|
from pathlib import Path
|
|
@@ -15,7 +16,7 @@ from everest.util.forward_models import (
|
|
|
15
16
|
parse_forward_model_file,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
from .install_job_config import
|
|
19
|
+
from .install_job_config import InstallForwardModelStepConfig
|
|
19
20
|
|
|
20
21
|
_VARIABLE_ERROR_MESSAGE = (
|
|
21
22
|
"Variable {name} must define {variable_type} value either"
|
|
@@ -39,6 +40,8 @@ _RESERVED_WORDS = [
|
|
|
39
40
|
"total_objective_value",
|
|
40
41
|
]
|
|
41
42
|
|
|
43
|
+
_OVERWRITE_MESSAGE = "Are you overwriting other parts of install_data?"
|
|
44
|
+
|
|
42
45
|
|
|
43
46
|
class InstallDataContext:
|
|
44
47
|
def __init__(
|
|
@@ -70,28 +73,44 @@ class InstallDataContext:
|
|
|
70
73
|
source = item.source
|
|
71
74
|
target = item.target
|
|
72
75
|
|
|
73
|
-
if "<
|
|
76
|
+
if "<REALIZATION_ID>" not in source:
|
|
74
77
|
self._set_symlink(source, target, None)
|
|
75
78
|
|
|
76
79
|
return self
|
|
77
80
|
|
|
78
81
|
def _set_symlink(self, source: str, target: str, realization: int | None) -> None:
|
|
79
82
|
if realization is not None:
|
|
80
|
-
source = source.replace("<
|
|
81
|
-
target = target.replace("<
|
|
83
|
+
source = source.replace("<REALIZATION_ID>", str(realization))
|
|
84
|
+
target = target.replace("<REALIZATION_ID>", str(realization))
|
|
82
85
|
|
|
83
86
|
tmp_target = Path(self._temp_dir.name) / Path(target)
|
|
84
87
|
if tmp_target.exists():
|
|
88
|
+
if tmp_target.is_dir() and not tmp_target.is_symlink():
|
|
89
|
+
raise ValueError(
|
|
90
|
+
"Cannot make symlink due to existing directory at target location"
|
|
91
|
+
f" {tmp_target}. " + _OVERWRITE_MESSAGE
|
|
92
|
+
)
|
|
85
93
|
tmp_target.unlink()
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
try:
|
|
95
|
+
tmp_target.parent.mkdir(parents=True, exist_ok=True)
|
|
96
|
+
tmp_target.symlink_to(as_abs_path(source, self._config_dir))
|
|
97
|
+
except FileExistsError as err:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"Cannot install data {source} into {target} due to existing "
|
|
100
|
+
"file or directory. " + _OVERWRITE_MESSAGE
|
|
101
|
+
) from err
|
|
88
102
|
|
|
89
103
|
def add_links_for_realization(self, realization: int) -> None:
|
|
90
104
|
for data in self._install_data:
|
|
91
|
-
if data.source is not None and "<
|
|
105
|
+
if data.source is not None and "<REALIZATION_ID>" in data.source:
|
|
92
106
|
self._set_symlink(data.source, data.target, realization)
|
|
93
107
|
|
|
94
|
-
def __exit__(
|
|
108
|
+
def __exit__(
|
|
109
|
+
self,
|
|
110
|
+
exc_type: type[BaseException] | None,
|
|
111
|
+
exc_value: BaseException | None,
|
|
112
|
+
exc_tb: types.TracebackType | None,
|
|
113
|
+
) -> None:
|
|
95
114
|
if self._temp_dir:
|
|
96
115
|
self._temp_dir.cleanup()
|
|
97
116
|
os.chdir(self._cwd)
|
|
@@ -177,7 +196,7 @@ def unique_items(items: Sequence[T]) -> Sequence[T]:
|
|
|
177
196
|
|
|
178
197
|
|
|
179
198
|
def valid_range(range_value: tuple[float, float]) -> tuple[float, float]:
|
|
180
|
-
if range_value[0] >= range_value[1]:
|
|
199
|
+
if range_value is not None and range_value[0] >= range_value[1]:
|
|
181
200
|
raise ValueError("scaled_range must be a valid range [a, b], where a < b.")
|
|
182
201
|
return range_value
|
|
183
202
|
|
|
@@ -229,8 +248,8 @@ def as_abs_path(path: str, config_dir: str) -> str:
|
|
|
229
248
|
|
|
230
249
|
|
|
231
250
|
def expand_model_id_paths(path_source: str, realizations: list[int]) -> list[str]:
|
|
232
|
-
if "<
|
|
233
|
-
return [path_source.replace("<
|
|
251
|
+
if "<REALIZATION_ID>" in path_source:
|
|
252
|
+
return [path_source.replace("<REALIZATION_ID>", str(r)) for r in realizations]
|
|
234
253
|
return [path_source]
|
|
235
254
|
|
|
236
255
|
|
|
@@ -238,7 +257,8 @@ def check_path_exists(
|
|
|
238
257
|
path_source: str, config_path: Path | None, realizations: list[int]
|
|
239
258
|
) -> None:
|
|
240
259
|
"""Check if the given path exists. If the given path contains <CONFIG_PATH>
|
|
241
|
-
or
|
|
260
|
+
or REALIZATION_ID they will be expanded and all instances of expanded paths
|
|
261
|
+
need to exist.
|
|
242
262
|
"""
|
|
243
263
|
if not isinstance(path_source, str):
|
|
244
264
|
raise ValueError(
|
|
@@ -272,8 +292,7 @@ def check_writeable_path(path_source: str, config_path: Path) -> None:
|
|
|
272
292
|
if os.access(path, os.W_OK | os.X_OK):
|
|
273
293
|
break
|
|
274
294
|
elif os.path.isfile(path):
|
|
275
|
-
|
|
276
|
-
raise ValueError(f"File {path} exists, cannot create path {path_source}")
|
|
295
|
+
raise ValueError(f"{path} is a file, cannot create folders inside it")
|
|
277
296
|
parent = os.path.dirname(path)
|
|
278
297
|
if parent == path: # ie, if path is root
|
|
279
298
|
break
|
|
@@ -284,7 +303,7 @@ def check_writeable_path(path_source: str, config_path: Path) -> None:
|
|
|
284
303
|
|
|
285
304
|
|
|
286
305
|
def validate_forward_model_configs(
|
|
287
|
-
forward_model: list[str], install_jobs: list[
|
|
306
|
+
forward_model: list[str], install_jobs: list[InstallForwardModelStepConfig]
|
|
288
307
|
) -> None:
|
|
289
308
|
if not forward_model:
|
|
290
309
|
return
|
everest/config_file_loader.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
|
|
3
1
|
import logging
|
|
4
2
|
import os
|
|
5
3
|
import re
|
|
6
4
|
from io import StringIO
|
|
5
|
+
from pathlib import Path
|
|
7
6
|
from typing import Any
|
|
8
7
|
|
|
9
8
|
import jinja2
|
|
@@ -25,29 +24,28 @@ SUBSTITUTION_PATTERN = r"(r\{\{.*?\}\})"
|
|
|
25
24
|
|
|
26
25
|
# Jinja vars which should NOT be included in definitions portion of config.
|
|
27
26
|
ERT_CONFIG_TEMPLATES = {
|
|
28
|
-
"realization": "
|
|
27
|
+
"realization": "REALIZATION_ID",
|
|
29
28
|
"runpath_file": "RUNPATH_FILE",
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
def load_yaml(file_name: str, safe: bool = False) -> dict[str, Any]:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
raise YAMLError(str(exc)) from exc
|
|
33
|
+
input_data = Path(file_name).read_text(encoding="utf-8").splitlines()
|
|
34
|
+
try:
|
|
35
|
+
yaml = YAML(typ="safe", pure=True) if safe else YAML()
|
|
36
|
+
yaml.preserve_quotes = True
|
|
37
|
+
return yaml.load("\n".join(input_data))
|
|
38
|
+
except YAMLError as exc:
|
|
39
|
+
if hasattr(exc, "problem_mark"):
|
|
40
|
+
mark = exc.problem_mark
|
|
41
|
+
raise YAMLError(
|
|
42
|
+
str(exc)
|
|
43
|
+
+ "\nError in line: {}\n {}^)".format(
|
|
44
|
+
input_data[mark.line], " " * mark.column
|
|
45
|
+
)
|
|
46
|
+
) from exc
|
|
47
|
+
else:
|
|
48
|
+
raise YAMLError(str(exc)) from exc
|
|
51
49
|
|
|
52
50
|
|
|
53
51
|
def _get_definitions(
|
|
@@ -67,7 +65,7 @@ def _get_definitions(
|
|
|
67
65
|
f"Internal key {key} specified by user as {defs[key]}. "
|
|
68
66
|
f"Overriding as {val}"
|
|
69
67
|
)
|
|
70
|
-
defs[key] = f"<{val}>" # ert uses <
|
|
68
|
+
defs[key] = f"<{val}>" # ert uses <REALIZATION_ID> as format
|
|
71
69
|
else:
|
|
72
70
|
logging.getLogger(EVEREST).warning("Empty configuration file provided!")
|
|
73
71
|
|
|
@@ -160,6 +158,17 @@ def yaml_file_to_substituted_config_dict(config_path: str) -> dict[str, Any]:
|
|
|
160
158
|
# Replace in definitions
|
|
161
159
|
config = jenv.from_string(txt).render(**definitions)
|
|
162
160
|
|
|
161
|
+
# Handle deprecated use of <GEO_ID>:
|
|
162
|
+
config, count = re.subn(
|
|
163
|
+
rf"<\s*{re.escape('GEO_ID')}\s*>", "<REALIZATION_ID>", config
|
|
164
|
+
)
|
|
165
|
+
if count > 0:
|
|
166
|
+
message = r"<GEO_ID> is deprecated, please replace with 'r{{realization}}'."
|
|
167
|
+
print(message)
|
|
168
|
+
logging.getLogger(EVEREST).warning(
|
|
169
|
+
"Deprecated key <GEO_ID> replaced by <REALIZATION_ID>."
|
|
170
|
+
)
|
|
171
|
+
|
|
163
172
|
# Load the config with definitions again as yaml
|
|
164
173
|
yaml = YAML(typ="safe", pure=True).load(config)
|
|
165
174
|
|
everest/detached/__init__.py
CHANGED
|
@@ -4,28 +4,22 @@ Client methods for interacting with everserver
|
|
|
4
4
|
|
|
5
5
|
from .client import (
|
|
6
6
|
PROXY,
|
|
7
|
-
ExperimentState,
|
|
8
|
-
everserver_status,
|
|
9
7
|
server_is_running,
|
|
10
8
|
start_experiment,
|
|
11
9
|
start_monitor,
|
|
12
10
|
start_server,
|
|
13
11
|
stop_server,
|
|
14
|
-
update_everserver_status,
|
|
15
12
|
wait_for_server,
|
|
16
13
|
wait_for_server_to_stop,
|
|
17
14
|
)
|
|
18
15
|
|
|
19
16
|
__all__ = [
|
|
20
17
|
"PROXY",
|
|
21
|
-
"ExperimentState",
|
|
22
|
-
"everserver_status",
|
|
23
18
|
"server_is_running",
|
|
24
19
|
"start_experiment",
|
|
25
20
|
"start_monitor",
|
|
26
21
|
"start_server",
|
|
27
22
|
"stop_server",
|
|
28
|
-
"update_everserver_status",
|
|
29
23
|
"wait_for_server",
|
|
30
24
|
"wait_for_server_to_stop",
|
|
31
25
|
]
|