Skip to content

Commit

Permalink
Simulation metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
asnyv committed Apr 28, 2020
1 parent 843bda0 commit 48afc8c
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 231 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
{
"METRIC":
{
"SM3": "Sm³",
"METRIC": {
"M": "m",
"M3": "",
"RM3": "",
"SECONDS": "seconds",
"DAYS": "days",
"YEARS": "years",
"KG/M3": "kg/m³",
"BARSA": "bara",
"bars": "bar",
"K": "K",
"C": "\u00B0C",
"CP": "cP",
"MD": "mD",
"SM3": "Sm³",
"RM3": "Rm³",
"SM3/DAY": "Sm³/day",
"RM3/DAY": "m³/day",
"RM3/DAY": "Rm³/day",
"CPR3/DAY/BARS": "Rm³\u00D7cP/day/bar",
"MDM": "mD\u00D7m",
"KG": "kg",
"KG/DAY": "kg/day",
"SM3/SM3": "Sm³/Sm³",
"RM3/SM3": "m³/Sm³",
"BARSA": "bara",
"BARS": "barg",
"RM3/SM3": "Rm³/Sm³",
"SM3/RM3": "Sm³/Rm³",
"SM3/DAY/BARS": "Sm³/day/bar",
"SM3/D/B": "Sm³/day/bar",
"SECONDS": "s",
"DAYS": "days"
}
"KJ": "kJ",
"KJ/DAY": "kJ/day",
"SEC/D": "seconds/day"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
"RECOVERABLE_GAS": {"label": "Recoverable volume (gas zone)", "unit": "Sm³"},
"RECOVERABLE_TOTAL": {"label": "Recoverable volume (total)", "unit": "Sm³"}
}

32 changes: 21 additions & 11 deletions webviz_subsurface/_abbreviations/number_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,33 @@
import json
import pathlib
import warnings
from typing import Optional, Union
from typing import Optional, Union, List


_DATA_PATH = pathlib.Path(__file__).parent.absolute() / "abbreviation_data"

SI_PREFIXES = json.loads((_DATA_PATH / "si_prefixes.json").read_text())

TABLE_STATISTICS_BASE = [
(
i,
{
"type": "numeric",
"format": {"locale": {"symbol": ["", "unit_insert"]}, "specifier": "$.4s",},
},
)
for i in ["Mean", "Stddev", "Minimum", "P90", "P10", "Maximum"]
]

def table_statistics_base() -> List[tuple]:
return [
(
i,
{
"type": "numeric",
"format": {"locale": {"symbol": ["", ""]}, "specifier": "$.4s",},
},
)
if i != "Stddev"
else (
i,
{
"type": "numeric",
"format": {"locale": {"symbol": ["", ""]}, "specifier": "$.3s",},
},
)
for i in ["Mean", "Stddev", "Minimum", "P90", "P10", "Maximum"]
]


def si_prefixed(
Expand Down
48 changes: 44 additions & 4 deletions webviz_subsurface/_abbreviations/reservoir_simulation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import json
import pathlib
import warnings
from typing import Optional

import pandas as pd


_DATA_PATH = pathlib.Path(__file__).parent.absolute() / "abbreviation_data"
Expand All @@ -14,7 +17,7 @@
)


def simulation_unit_reformat(ecl_unit: str, unit_set: str = "METRIC"):
def simulation_unit_reformat(ecl_unit: str, unit_set: str = "METRIC") -> str:
"""Returns the simulation unit in a different, more human friendly, format if possible,
otherwise returns the simulation unit.
* `ecl_unit`: Reservoir simulation vector unit to reformat
Expand All @@ -23,15 +26,14 @@ def simulation_unit_reformat(ecl_unit: str, unit_set: str = "METRIC"):
return RESERVOIR_SIMULATION_UNIT_TERMINOLOGY[unit_set].get(ecl_unit, ecl_unit)


def simulation_vector_base(vector: str):
def simulation_vector_base(vector: str) -> str:
"""Returns base name of simulation vector
E.g. WOPR for WOPR:OP_1 and ROIP for ROIP_REG:1
"""

return vector.split(":", 1)[0].split("_", 1)[0]


def simulation_vector_description(vector: str):
def simulation_vector_description(vector: str) -> str:
"""Returns a more human friendly description of the simulation vector if possible,
otherwise returns the input as is.
"""
Expand Down Expand Up @@ -71,3 +73,41 @@ def simulation_vector_description(vector: str):
)

return description


def historical_vector(
vector: str,
smry_meta: Optional[pd.DataFrame] = None,
return_historical: Optional[bool] = True,
):
"""This function is trying to make a best guess on converting between historical and
non-historical vector names.
If return_historical is `True`, the corresponding guessed historical vector name
is returned if the guessed vector is thought to be a historical vector, else None is returned.
If `False` the corresponding non-historical vector name is returned, if the input vector is
thought to be a historical vector, else None is returned.
"""
smry_meta = None
parts = vector.split(":", 1)
if return_historical:
parts[0] += "H"
hist_vec = ":".join(parts)
return (
None
if historical_vector(hist_vec, smry_meta=smry_meta, return_historical=False)
is None
else hist_vec
)

if smry_meta is None:
if parts[0].endswith("H") and parts[0].startswith(("F", "G", "W")):
parts[0] = parts[0][:-1]
return ":".join(parts)
return None

try:
is_hist = smry_meta.is_historical[vector]
except KeyError:
is_hist = False
return parts[0][:-1] if is_hist else None
18 changes: 18 additions & 0 deletions webviz_subsurface/_datainput/fmu_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ def load_smry(
)


@CACHE.memoize(timeout=CACHE.TIMEOUT)
@webvizstore
def load_smry_meta(
ensemble_paths: dict,
ensemble_set_name: str = "EnsembleSet",
column_keys: Optional[list] = None,
) -> pd.DataFrame:
"""Finds metadata for the summary vectors in the ensemble set.
Note that we assume the same units for all ensembles.
(meaning that we update/overwrite when checking the next ensemble)
"""
ensemble_set = load_ensemble_set(ensemble_paths, ensemble_set_name)
smry_meta = {}
for ensname in ensemble_set.ensemblenames:
smry_meta.update(ensemble_set[ensname].get_smry_meta(column_keys=column_keys))
return pd.DataFrame(smry_meta).transpose()


@CACHE.memoize(timeout=CACHE.TIMEOUT)
@webvizstore
def get_realizations(
Expand Down
67 changes: 40 additions & 27 deletions webviz_subsurface/plugins/_inplace_volumes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np
import pandas as pd
import dash_table
from dash_table import DataTable
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
Expand All @@ -14,7 +14,7 @@

from .._datainput.inplace_volumes import extract_volumes
from .._abbreviations.volume_terminology import volume_description, volume_unit
from .._abbreviations.number_formatting import TABLE_STATISTICS_BASE
from .._abbreviations.number_formatting import table_statistics_base


class InplaceVolumes(WebvizPluginABC):
Expand Down Expand Up @@ -59,7 +59,7 @@ class InplaceVolumes(WebvizPluginABC):
"""

TABLE_STATISTICS = [("Response", {}), ("Group", {})] + TABLE_STATISTICS_BASE
TABLE_STATISTICS = [("Group", {})] + table_statistics_base()

def __init__(
self,
Expand Down Expand Up @@ -326,15 +326,17 @@ def layout(self):
id=self.ids("layout"),
children=[
html.Div(
style={"flex": 1},
children=[
html.P("Filters:", style={"font-weight": "bold"}),
html.Span("Filters:", style={"font-weight": "bold"}),
html.Div(
id=self.ids("filters"),
children=self.selector_dropdowns,
),
],
),
html.Div(
style={"flex": 5},
children=[
self.plot_options_layout,
html.Div(
Expand All @@ -345,10 +347,20 @@ def layout(self):
),
],
),
dash_table.DataTable(
id=self.ids("table"),
columns=[
{"name": i, "id": i} for i in InplaceVolumes.TABLE_STATISTICS
html.Div(
children=[
html.Div(
id=self.ids("table_title"),
style={"textAlign": "center"},
children="",
),
DataTable(
id=self.ids("table"),
sort_action="native",
filter_action="native",
page_action="native",
page_size=10,
),
],
),
]
Expand All @@ -360,6 +372,7 @@ def set_callbacks(self, app):
Output(self.ids("graph"), "figure"),
Output(self.ids("table"), "data"),
Output(self.ids("table"), "columns"),
Output(self.ids("table_title"), "children"),
],
self.vol_callback_inputs,
)
Expand Down Expand Up @@ -398,15 +411,19 @@ def _render_vol_chart(*args):
plot_traces.append(trace)
table.append(plot_table(dframe, response, name))
# Column specification
columns = table_columns(response)
# Else make a graph object
columns = [
{**{"name": i[0], "id": i[0]}, **i[1]}
for i in InplaceVolumes.TABLE_STATISTICS
]
# Make a graph object and return
return (
{
"data": plot_traces,
"layout": plot_layout(plot_type, response, theme=self.plotly_theme),
},
table,
columns,
f"{volume_description(response)} [{volume_unit(response)}]",
)

@app.callback(
Expand Down Expand Up @@ -468,7 +485,6 @@ def plot_table(dframe, response, name):
values = dframe[response]
try:
output = {
"Response": volume_description(response),
"Group": str(name),
"Minimum": values.min(),
"Maximum": values.max(),
Expand All @@ -483,19 +499,6 @@ def plot_table(dframe, response, name):
return output


@CACHE.memoize(timeout=CACHE.TIMEOUT)
def table_columns(response):
columns = [
{**{"name": i[0], "id": i[0]}, **i[1]} for i in InplaceVolumes.TABLE_STATISTICS
]
for col in columns:
try:
col["format"]["locale"]["symbol"] = ["", f"{volume_unit(response)}"]
except KeyError:
pass
return columns


@CACHE.memoize(timeout=CACHE.TIMEOUT)
def plot_layout(plot_type, response, theme):
layout = {}
Expand All @@ -507,17 +510,27 @@ def plot_layout(plot_type, response, theme):
"barmode": "overlay",
"bargap": 0.01,
"bargroupgap": 0.2,
"xaxis": {"title": volume_description(response)},
"xaxis": {
"title": f"{volume_description(response)} [{volume_unit(response)}]"
},
"yaxis": {"title": "Count"},
}
)
elif plot_type == "Box plot":
layout.update({"yaxis": {"title": volume_description(response)}})
layout.update(
{
"yaxis": {
"title": f"{volume_description(response)} [{volume_unit(response)}]"
}
}
)
else:
layout.update(
{
"margin": {"l": 40, "r": 40, "b": 30, "t": 10},
"yaxis": {"title": volume_description(response)},
"yaxis": {
"title": f"{volume_description(response)} [{volume_unit(response)}]"
},
"xaxis": {"title": "Realization"},
}
)
Expand Down
Loading

0 comments on commit 48afc8c

Please sign in to comment.