webviz-subsurface 0.2.37__py3-none-any.whl → 0.2.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. tests/unit_tests/plugin_tests/test_tornado_data.py +10 -1
  2. webviz_subsurface/_components/tornado/_tornado_bar_chart.py +31 -11
  3. webviz_subsurface/_components/tornado/_tornado_data.py +20 -2
  4. webviz_subsurface/_datainput/well_completions.py +2 -1
  5. webviz_subsurface/_providers/ensemble_table_provider/ensemble_table_provider_factory.py +4 -0
  6. webviz_subsurface/_utils/design_matrix.py +36 -0
  7. webviz_subsurface/plugins/_co2_leakage/_plugin.py +623 -493
  8. webviz_subsurface/plugins/_co2_leakage/_types.py +7 -0
  9. webviz_subsurface/plugins/_co2_leakage/_utilities/callbacks.py +96 -52
  10. webviz_subsurface/plugins/_co2_leakage/_utilities/co2volume.py +300 -82
  11. webviz_subsurface/plugins/_co2_leakage/_utilities/containment_info.py +31 -0
  12. webviz_subsurface/plugins/_co2_leakage/_utilities/initialization.py +16 -7
  13. webviz_subsurface/plugins/_co2_leakage/_utilities/surface_publishing.py +102 -9
  14. webviz_subsurface/plugins/_co2_leakage/views/mainview/mainview.py +14 -1
  15. webviz_subsurface/plugins/_co2_leakage/views/mainview/settings.py +181 -58
  16. webviz_subsurface/plugins/_parameter_analysis/_types.py +1 -0
  17. webviz_subsurface/plugins/_parameter_analysis/_utils/_parameters_model.py +10 -2
  18. webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_distributions_view/_settings/_visualization_type.py +2 -1
  19. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/METADATA +1 -1
  20. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/RECORD +25 -22
  21. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/LICENSE +0 -0
  22. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/LICENSE.chromedriver +0 -0
  23. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/WHEEL +0 -0
  24. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/entry_points.txt +0 -0
  25. {webviz_subsurface-0.2.37.dist-info → webviz_subsurface-0.2.39.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,10 @@
2
2
  import pandas as pd
3
3
  import pytest
4
4
 
5
- from webviz_subsurface._components.tornado._tornado_data import TornadoData
5
+ from webviz_subsurface._components.tornado._tornado_data import (
6
+ SensitivityType,
7
+ TornadoData,
8
+ )
6
9
 
7
10
 
8
11
  def test_tornado_data_init():
@@ -36,6 +39,7 @@ def test_tornado_data_init():
36
39
  "values": 11.0,
37
40
  "values_ref": -26.666666666666668,
38
41
  "reals": [0],
42
+ "senstype": "mc",
39
43
  }
40
44
  low_high_list = tornado_data._calculate_tornado_low_high_list(avg_list)
41
45
  assert low_high_list[0] == {
@@ -52,6 +56,7 @@ def test_tornado_data_init():
52
56
  "high_tooltip": 26.666666666666668,
53
57
  "true_high": 19.0,
54
58
  "high_reals": [1],
59
+ "senstype": "mc",
55
60
  }
56
61
 
57
62
  tornado_data = TornadoData(
@@ -72,6 +77,7 @@ def test_tornado_data_init():
72
77
  "high_tooltip": 13.5,
73
78
  "true_high": 19.0,
74
79
  "high_reals": [0, 1],
80
+ "senstype": SensitivityType.MONTE_CARLO,
75
81
  },
76
82
  {
77
83
  "low": 0.0,
@@ -87,6 +93,7 @@ def test_tornado_data_init():
87
93
  "high_tooltip": 0.0,
88
94
  "true_high": 5.5,
89
95
  "high_reals": [2, 3],
96
+ "senstype": SensitivityType.SCALAR,
90
97
  },
91
98
  {
92
99
  "low": 0.0,
@@ -102,6 +109,7 @@ def test_tornado_data_init():
102
109
  "high_tooltip": 20.0,
103
110
  "true_high": 25.5,
104
111
  "high_reals": [4, 5],
112
+ "senstype": SensitivityType.SCALAR,
105
113
  },
106
114
  {
107
115
  "low": 0.0,
@@ -117,5 +125,6 @@ def test_tornado_data_init():
117
125
  "high_tooltip": 5.300000000000001,
118
126
  "true_high": 10.8,
119
127
  "high_reals": [6, 7],
128
+ "senstype": SensitivityType.MONTE_CARLO,
120
129
  },
121
130
  ]
@@ -5,7 +5,7 @@ import plotly.graph_objects as go
5
5
 
6
6
  from webviz_subsurface._abbreviations.number_formatting import si_prefixed
7
7
 
8
- from ._tornado_data import TornadoData
8
+ from ._tornado_data import SensitivityType, TornadoData
9
9
 
10
10
 
11
11
  class TornadoBarChart:
@@ -136,9 +136,25 @@ class TornadoBarChart:
136
136
  hovertext.append(text)
137
137
  return hovertext
138
138
 
139
+ def get_sensitivity_colors(self, case: str) -> List:
140
+ """Create color list for bars based on sensitivity type
141
+ If colors are set by sensitivity, just create a color per sensitivty.
142
+ If not handle scalar and mc sensitivities separately.
143
+ For scalar, that is sensitivities with two "cases", use separate colors for each case.
144
+ For mc, use one color.
145
+ """
146
+ if self._color_by_sens:
147
+ return self.create_color_list(self._tornadotable["sensname"])
148
+ colors = []
149
+ for _, row in self._tornadotable.iterrows():
150
+ if row["senstype"] == SensitivityType.MONTE_CARLO or case == "low":
151
+ colors.append(self._plotly_theme["layout"]["colorway"][0])
152
+ else:
153
+ colors.append(self._plotly_theme["layout"]["colorway"][1])
154
+ return colors
155
+
139
156
  @property
140
157
  def data(self) -> List:
141
- colors = self.create_color_list(self._tornadotable["sensname"].unique())
142
158
  return [
143
159
  {
144
160
  "type": "bar",
@@ -157,7 +173,7 @@ class TornadoBarChart:
157
173
  "orientation": "h",
158
174
  "marker": {
159
175
  "line": {"width": 1.5, "color": "black"},
160
- "color": colors if self._color_by_sens else None,
176
+ "color": self.get_sensitivity_colors("low"),
161
177
  },
162
178
  },
163
179
  {
@@ -177,7 +193,7 @@ class TornadoBarChart:
177
193
  "orientation": "h",
178
194
  "marker": {
179
195
  "line": {"width": 1.5, "color": "black"},
180
- "color": colors if self._color_by_sens else None,
196
+ "color": self.get_sensitivity_colors("high"),
181
197
  },
182
198
  },
183
199
  ]
@@ -193,6 +209,15 @@ class TornadoBarChart:
193
209
 
194
210
  @property
195
211
  def scatter_data(self) -> List[Dict]:
212
+ def get_color(case_name_arr: pd.Series, case_type_arr: pd.Series) -> List:
213
+ colors = []
214
+ for case_name, case_type in zip(case_name_arr, case_type_arr):
215
+ if case_name == "low" or case_type == SensitivityType.MONTE_CARLO:
216
+ colors.append(self._plotly_theme["layout"]["colorway"][0])
217
+ else:
218
+ colors.append(self._plotly_theme["layout"]["colorway"][1])
219
+ return colors
220
+
196
221
  return [
197
222
  {
198
223
  "type": "scatter",
@@ -202,14 +227,9 @@ class TornadoBarChart:
202
227
  "text": df["REAL"],
203
228
  "hovertemplate": "REAL: <b>%{text}</b><br>"
204
229
  + "X: <b>%{x:.1f}</b> <extra></extra>",
205
- "marker": {
206
- "size": 15,
207
- "color": self._plotly_theme["layout"]["colorway"][0]
208
- if case == "low"
209
- else self._plotly_theme["layout"]["colorway"][1],
210
- },
230
+ "marker": {"size": 15, "color": get_color(df["case"], df["casetype"])},
211
231
  }
212
- for case, df in self._realtable.groupby("case")
232
+ for _, df in self._realtable.groupby("case")
213
233
  ]
214
234
 
215
235
  @property
@@ -3,6 +3,15 @@ from typing import Dict, List, Optional, Union
3
3
  import numpy as np
4
4
  import pandas as pd
5
5
 
6
+ from webviz_subsurface._utils.enum_shim import StrEnum
7
+
8
+
9
+ class SensitivityType(StrEnum):
10
+ """Sensitivity types used in Tornado analysis."""
11
+
12
+ SCALAR = "scalar"
13
+ MONTE_CARLO = "mc"
14
+
6
15
 
7
16
  class TornadoData:
8
17
  REQUIRED_COLUMNS = ["REAL", "SENSNAME", "SENSCASE", "SENSTYPE", "VALUE"]
@@ -50,7 +59,11 @@ class TornadoData:
50
59
  def _create_real_df(self, dframe: pd.DataFrame) -> pd.DataFrame:
51
60
  """Make dataframe with value and case info per realization"""
52
61
  realdf = dframe[self.REQUIRED_COLUMNS].rename(
53
- columns={"SENSNAME": "sensname", "SENSCASE": "senscase"}
62
+ columns={
63
+ "SENSNAME": "sensname",
64
+ "SENSCASE": "senscase",
65
+ "SENSTYPE": "senstype",
66
+ }
54
67
  )
55
68
 
56
69
  sensitivities = self._tornadotable["sensname"].unique()
@@ -61,7 +74,7 @@ class TornadoData:
61
74
  casemask = realdf["REAL"].isin(val[f"real_{case}"])
62
75
  realdf.loc[casemask, "case"] = case
63
76
 
64
- mc_mask = realdf["SENSTYPE"] == "mc"
77
+ mc_mask = realdf["senstype"] == "mc"
65
78
  realdf["casetype"] = np.where(mc_mask, "mc", realdf["case"])
66
79
  realdf["sensname_case"] = np.where(
67
80
  mc_mask,
@@ -127,6 +140,7 @@ class TornadoData:
127
140
  sens_case_df["VALUE"].mean()
128
141
  ),
129
142
  "reals": list(map(int, sens_case_df["REAL"])),
143
+ "senstype": SensitivityType.SCALAR,
130
144
  }
131
145
  )
132
146
  # If `SENSTYPE` is monte carlo get p10, p90
@@ -162,6 +176,7 @@ class TornadoData:
162
176
  "values": p90,
163
177
  "values_ref": self._scale_to_ref(p90),
164
178
  "reals": low_reals,
179
+ "senstype": SensitivityType.MONTE_CARLO,
165
180
  }
166
181
  )
167
182
  avg_per_sensitivity.append(
@@ -171,6 +186,7 @@ class TornadoData:
171
186
  "values": p10,
172
187
  "values_ref": self._scale_to_ref(p10),
173
188
  "reals": high_reals,
189
+ "senstype": SensitivityType.MONTE_CARLO,
174
190
  }
175
191
  )
176
192
 
@@ -198,6 +214,7 @@ class TornadoData:
198
214
  high["reals"] = []
199
215
  high["senscase"] = None
200
216
  high["values"] = self.reference_average
217
+
201
218
  else:
202
219
  low = (
203
220
  low.copy()
@@ -218,6 +235,7 @@ class TornadoData:
218
235
  "true_low": low["values"],
219
236
  "low_reals": low["reals"],
220
237
  "sensname": sensname,
238
+ "senstype": sens_name_df["senstype"].unique()[0],
221
239
  "high": self.calc_high_x(low["values_ref"], high["values_ref"]),
222
240
  "high_base": self.calc_high_base(
223
241
  low["values_ref"], high["values_ref"]
@@ -15,7 +15,8 @@ import pandas as pd
15
15
  # NOTE: Functions in this file cannot be used
16
16
  # on non-Linux OSes.
17
17
  try:
18
- from res2df.resdatafiles import ResdataFiles, common
18
+ from res2df import common
19
+ from res2df.resdatafiles import ResdataFiles
19
20
  except ImportError:
20
21
  pass
21
22
 
@@ -10,6 +10,9 @@ from webviz_config.webviz_factory import WebvizFactory
10
10
  from webviz_config.webviz_factory_registry import WEBVIZ_FACTORY_REGISTRY
11
11
  from webviz_config.webviz_instance_info import WebvizRunMode
12
12
 
13
+ from webviz_subsurface._utils.design_matrix import (
14
+ rename_design_matrix_parameter_columns,
15
+ )
13
16
  from webviz_subsurface._utils.perf_timer import PerfTimer
14
17
 
15
18
  from ..ensemble_summary_provider._arrow_unsmry_import import (
@@ -283,6 +286,7 @@ class EnsembleTableProviderFactory(WebvizFactory):
283
286
  raise ValueError(
284
287
  f"Failed to load 'parameter.txt' files for ensemble {ens_path}."
285
288
  )
289
+ ensemble_df = rename_design_matrix_parameter_columns(ensemble_df)
286
290
 
287
291
  elapsed_load_parameters_s = timer.lap_s()
288
292
 
@@ -0,0 +1,36 @@
1
+ import logging
2
+
3
+ import pandas as pd
4
+
5
+ LOGGER = logging.getLogger(__name__)
6
+
7
+
8
+ def rename_design_matrix_parameter_columns(parameter_df: pd.DataFrame) -> pd.DataFrame:
9
+ """Given a dataframe of parameters, checks if the DESIGN_MATRIX prefix is present.
10
+ If present assume this is a design matrix run. Return the dataframe with the prefix
11
+ removed. Also do a check if removing the prefix result in any duplicates.
12
+ If duplicates remove those and give a warning.
13
+ """
14
+
15
+ if any(col.startswith("DESIGN_MATRIX:") for col in parameter_df.columns):
16
+ original_columns = parameter_df.columns
17
+ stripped_columns = original_columns.str.replace(
18
+ r"^DESIGN_MATRIX:", "", regex=True
19
+ )
20
+ rename_map = {
21
+ old: new
22
+ for old, new in zip(original_columns, stripped_columns)
23
+ if old != new
24
+ }
25
+ conflict_names = set(rename_map.values()) & set(original_columns)
26
+ if conflict_names:
27
+ LOGGER.info(
28
+ "DESIGN_MATRIX run detected, but non design matrix parameters was found."
29
+ )
30
+ LOGGER.info(
31
+ f"The following parameters will be dropped: {sorted(conflict_names)}"
32
+ )
33
+ parameter_df = parameter_df.drop(columns=conflict_names)
34
+
35
+ parameter_df = parameter_df.rename(columns=rename_map)
36
+ return parameter_df