diff --git a/README.md b/README.md index abe2e39..e41b81f 100755 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ If you are interested in a specific version (e.g., v2026.04) or in modifying the git clone https://github.com/cssr-tools/plopm.git # Get inside the folder cd plopm -# For a specific version (e.g., v2026.04), or else skip this step (i.e., edge version) -git checkout v2026.04 # Create virtual environment python3 -m venv vplopm # Activate virtual environment diff --git a/dev-requirements.txt b/dev-requirements.txt index 1072b9a..1982f84 100755 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,9 +2,12 @@ black numpydoc mypy pillow +pydata_sphinx_theme pylint pytest-cov pytest-xdist ruff sphinx +sphinx_copybutton +sphinx_design sphinx-rtd-theme diff --git a/docs/Makefile b/docs/Makefile index 9075617..94889f9 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,25 +1,29 @@ -# Minimal makefile for Sphinx documentation -# +# Makefile for the plopm Sphinx documentation. -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = text -BUILDDIR = _build +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = text +BUILDDIR = _build +APIDIR = text/api + +.PHONY: help clean api html linkcheck docs -# Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -.PHONY: help Makefile +clean: + rm -rf "$(BUILDDIR)" + +api: + @mkdir -p "$(APIDIR)" + sphinx-apidoc -e -f -o "$(APIDIR)" ../src/plopm + +html: api + @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - sphinx-apidoc --private -e -f -o text ../src/plopm - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +linkcheck: + @$(SPHINXBUILD) -M linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -github: - @make html - cp -a _build/html/. . +# Preserve the repository's current publishing workflow when needed. +docs: html + cp -a "$(BUILDDIR)/html/." . diff --git a/docs/_images/about.png b/docs/_images/about.png deleted file mode 100644 index e47e3f5..0000000 Binary files a/docs/_images/about.png and /dev/null differ diff --git a/docs/_images/docs_z_flag.png b/docs/_images/docs_z_flag.png deleted file mode 100644 index c5c358d..0000000 Binary files a/docs/_images/docs_z_flag.png and /dev/null differ diff --git a/docs/_images/plopm.png b/docs/_images/plopm.png index 0c74932..6dbf24e 100644 Binary files a/docs/_images/plopm.png and b/docs/_images/plopm.png differ diff --git a/docs/_images/sgas_beautiful.png b/docs/_images/sgas_beautiful.png new file mode 100644 index 0000000..fe53e37 Binary files /dev/null and b/docs/_images/sgas_beautiful.png differ diff --git a/docs/_images/spe11b_sgas_i,1,k_t5.png b/docs/_images/spe11b_sgas_i,1,k_t5.png new file mode 100644 index 0000000..a14f0c4 Binary files /dev/null and b/docs/_images/spe11b_sgas_i,1,k_t5.png differ diff --git a/docs/_images/spe11c_pressure_i,j,1:120_t2.png b/docs/_images/spe11c_pressure_i,j,1:120_t2.png new file mode 100644 index 0000000..a8dfb68 Binary files /dev/null and b/docs/_images/spe11c_pressure_i,j,1:120_t2.png differ diff --git a/docs/_images/spe11c_satnum_i,14,k_t2.png b/docs/_images/spe11c_satnum_i,14,k_t2.png new file mode 100644 index 0000000..5c5511d Binary files /dev/null and b/docs/_images/spe11c_satnum_i,14,k_t2.png differ diff --git a/docs/_images/spe11c_sgas_55,j,k_t2.png b/docs/_images/spe11c_sgas_55,j,k_t2.png new file mode 100644 index 0000000..7505b69 Binary files /dev/null and b/docs/_images/spe11c_sgas_55,j,k_t2.png differ diff --git a/docs/_images/spe11c_sgas_i,14,k_t2.png b/docs/_images/spe11c_sgas_i,14,k_t2.png new file mode 100644 index 0000000..9ddb9b4 Binary files /dev/null and b/docs/_images/spe11c_sgas_i,14,k_t2.png differ diff --git a/docs/_images/spe11c_sgas_i,j,14_t2.png b/docs/_images/spe11c_sgas_i,j,14_t2.png new file mode 100644 index 0000000..b87fdc8 Binary files /dev/null and b/docs/_images/spe11c_sgas_i,j,14_t2.png differ diff --git a/docs/_images/spe11c_temp.gif b/docs/_images/spe11c_temp.gif new file mode 100644 index 0000000..07ca7bc Binary files /dev/null and b/docs/_images/spe11c_temp.gif differ diff --git a/docs/_modules/index.html b/docs/_modules/index.html new file mode 100644 index 0000000..83ade7d --- /dev/null +++ b/docs/_modules/index.html @@ -0,0 +1,536 @@ + + + + + + + + + + Overview: module code — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + + + + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/config/config.html b/docs/_modules/plopm/config/config.html new file mode 100644 index 0000000..e348fd7 --- /dev/null +++ b/docs/_modules/plopm/config/config.html @@ -0,0 +1,920 @@ + + + + + + + + + + plopm.config.config — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.config.config

+# SPDX-FileCopyrightText: 2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=C0103,R0902
+
+"""Configuration and simulation-data models shared across plopm workflows.
+
+PlopmConfig stores command-line options and normalized runtime settings used to
+create summary plots, spatial maps, animations, and VTK output. SimData stores
+OPM file handles, grid dimensions, and cell data loaded for one simulation case.
+
+Both objects are mutable because CLI values are normalized and simulation data
+are populated progressively during processing.
+"""
+
+from dataclasses import dataclass, field
+
+import numpy as np
+from numpy.typing import NDArray
+from opm.io.ecl import EclFile as OpmFile
+from opm.io.ecl import EGrid as OpmGrid
+from opm.io.ecl import ERst as OpmRestart
+
+
+
+[docs] +@dataclass(slots=True) +class PlopmConfig: + """Options and runtime settings for a plopm operation. + + Most list fields contain one value per variable, case, or subplot after + initialization. Values read from the CLI are normalized before plotting so + downstream functions can use consistent indexing. + + Attributes + ---------- + gif, csv, png, vtk + Whether GIF, CSV, PNG, or VTK output is active for the current run. + equal_aspect + Whether spatial maps use the same scale along both coordinate axes. + remove_duplicate_labels + Whether repeated axis labels are hidden in subplot layouts. + list_variables + Whether available INIT, UNRST, and summary variables are printed. + gif_loop + Whether generated GIF animations repeat after the final frame. + step_plot + Whether one-dimensional series are drawn as step plots. + global_range + Whether map limits and features are evaluated globally instead of only + within the selected slice. + rst_range + Whether PNG color limits are evaluated over the restart range. + sensor + Whether one-dimensional values are extracted at a grid-cell sensor. + layer + Whether one-dimensional values are extracted along a grid axis or layer. + csv_column_summary + Whether a one-dimensional series is read from CSV columns. + discrete + Whether the current spatial quantity uses discrete color categories. + fontsize + Base font size used in generated figures. + mask_threshold + Threshold applied to the selected mask variable. + gif_interval + Delay between GIF frames. + stress_coefficient + Vertical stress coefficient used for caprock-integrity quantities. + xscale, yscale + Factors converting grid coordinates to the requested spatial units. + ensemble + Ensemble mode controlling uncertainty bands and bounding members. + ncolors + Number of case-dependent styles used for summary plots. + color_log_ticks + Tick values used on logarithmic colorbars. + case_labels + User-provided case names used in legends and ensemble labels. + cases + Simulation-case paths grouped as requested by the CLI. + dual_grid + Per-variable flags enabling dual-porosity grid handling. + subplot_grid + Requested subplot rows and columns. + variables + Variables or variable expressions requested for processing. + filters + Property-filter expressions applied per case or variable. + title + Per-plot titles. + clim + Lower and upper color limits for spatial maps. + figsize + Figure width and height for each generated plot. + min_threshold, max_threshold + Limits outside which quantity values are hidden. + grid_edges + Per-map settings controlling cell-edge drawing. + colorbar_tick_count + Requested number of colorbar ticks. + legend_labels + Labels for cases, variables, or ensemble bounds. + hide_map_elements + Map components to omit, such as axes, labels, or colorbars. + time_units + Requested time unit for each one-dimensional plot. + scale_factor + Multipliers applied to plotted or exported quantity values. + axis_grid + Per-plot settings controlling the Matplotlib axis grid. + dpi + Output resolution for each generated figure. + colorbar_ticks + Explicit colorbar tick values. + legend_location + Per-plot legend placement. + vtk_format + VTK data type selected for each exported variable. + vtk_names + Variable names written to VTK cell-data arrays. + color_log + Flags selecting logarithmic color normalization. + rotation + Rotation angles applied to grid coordinates, in degrees. + filename + Output filenames normalized per requested plot. + translation + Coordinate translations applied after rotation. + restart + Selected OPM restart report steps. + aggregation + Aggregation method applied through a slice or selected cells. + distance + Distance method and target, such as a sensor or model boundaries. + histogram + Histogram settings, including the requested bins. + xlabel, ylabel + Per-plot axis labels. + xformat, yformat + Format strings used for axis tick labels. + xtick_count, ytick_count + Requested numbers of major ticks. + xlog, ylog + Flags selecting logarithmic axes. + xlim, ylim + Per-plot axis limits. + vsum + Summary-variable expressions prepared for plotting. + summary + Loaded or derived summary-series values. + time + Time coordinates associated with summary values. + wells, faults + Parsed feature locations used in spatial maps. + slice + Parsed i, j, and k selections used by all workflows. + csv_columns + CSV column settings retained in parsed per-plot form. + mass_vars + Supported component-mass quantities. + summary_mass + Summary vectors converted from standard volume to mass. + mass_fracs + Supported component mass-fraction quantities. + caprock_vars + Supported caprock-integrity quantities. + linewidth_values + Default line widths before per-variable normalization. + units + Display units associated with requested quantities. + cb_formats + Normalized numeric formats used for colorbar labels. + colormaps + Colormaps assigned to spatial variables. + disc_colormaps + Available colormaps suitable for discrete values. + linestyle, linewidth, colors + Normalized styles used by summary plots. + colors_default, linestyle_default + Default style sequences used when none are supplied. + colorbar_position + Relative position and size of an explicitly placed colorbar axis. + difference_input + Second case, folder, or file used to calculate differences. + colors_raw + Color specification received from the CLI before normalization. + output_dir + Directory in which generated files are written. + case + Primary case path used for file detection and classification. + fill_between_style + Colors and opacity values for ensemble uncertainty bands. + colorbar_format + Colorbar format specification received from the CLI. + fc + Figure or axes face color. + inactive_color + Color assigned to inactive grid cells. + mask_variable + Variable used to mask spatial-map values. + suptitle + Figure-level title shared by all subplots. + colorbar_label + User-provided colorbar label. + slice_mode + Mode used when retaining wells or faults in an aggregated slice. + xunits, yunits + Requested spatial unit codes for both coordinate axes. + xunit, yunit + Formatted spatial unit labels shown on the axes. + slices + Normalized half-open ranges used for spatial slice aggregation. + csv_cols + Normalized CSV column indices used for gridded CSV data. + """ + + # Output modes and processing switches + gif: bool = False + csv: bool = False + png: bool = False + vtk: bool = False + equal_aspect: bool = False + remove_duplicate_labels: bool = False + list_variables: bool = False + gif_loop: bool = False + step_plot: bool = False + global_range: bool = False + rst_range: bool = False # Evaluate color limits across restart steps + sensor: bool = False + layer: bool = False + csv_column_summary: bool = False + discrete: bool = True + + # Scalar plot and animation settings + fontsize: float = 0.0 + mask_threshold: float = 0.0 + gif_interval: float = 0.0 + stress_coefficient: float = 0.0 + xscale: float = 1.0 + yscale: float = 1.0 + ensemble: int = 0 # 0: off; 1: band; 2: bounds; 3: both + ncolors: int = 1 + + # Input cases, variables, and normalized selections + color_log_ticks: list = field(default_factory=list) + case_labels: list = field(default_factory=list) # Before path expansion + cases: list = field(default_factory=list) # Nested groups of case stems + dual_grid: list = field(default_factory=list) + subplot_grid: list = field(default_factory=list) + variables: list = field(default_factory=list) + filters: list = field(default_factory=list) + + # Figure, subplot, and axis settings + title: list = field(default_factory=list) + clim: list = field(default_factory=list) + figsize: list = field(default_factory=list) + min_threshold: list = field(default_factory=list) + max_threshold: list = field(default_factory=list) + + # Color, line, and map styling + grid_edges: list = field(default_factory=list) + colorbar_tick_count: list = field(default_factory=list) + legend_labels: list = field(default_factory=list) + hide_map_elements: list = field(default_factory=list) + time_units: list = field(default_factory=list) + scale_factor: list = field(default_factory=list) + axis_grid: list = field(default_factory=list) + dpi: list = field(default_factory=list) + colorbar_ticks: list = field(default_factory=list) + legend_location: list = field(default_factory=list) + + # Generated output names and VTK settings + vtk_format: list = field(default_factory=list) + vtk_names: list = field(default_factory=list) + color_log: list = field(default_factory=list) + rotation: list = field(default_factory=list) + filename: list = field(default_factory=list) + translation: list = field(default_factory=list) + restart: list = field(default_factory=list) + aggregation: list = field(default_factory=list) + distance: list = field(default_factory=list) + histogram: list = field(default_factory=list) + xlabel: list = field(default_factory=list) + xformat: list = field(default_factory=list) + xtick_count: list = field(default_factory=list) + xlog: list = field(default_factory=list) + xlim: list = field(default_factory=list) + ylabel: list = field(default_factory=list) + yformat: list = field(default_factory=list) + ytick_count: list = field(default_factory=list) + ylog: list = field(default_factory=list) + ylim: list = field(default_factory=list) + + # Summary data, features, and derived quantities + vsum: list = field(default_factory=list) + summary: list = field(default_factory=list) + time: list = field(default_factory=list) + wells: list = field(default_factory=list) + faults: list = field(default_factory=list) + slice: list = field(default_factory=list) # Parsed i, j, k selections + csv_columns: list = field(default_factory=list) + mass_vars: list = field(default_factory=list) + summary_mass: list = field(default_factory=list) + mass_fracs: list = field(default_factory=list) + caprock_vars: list = field(default_factory=list) + linewidth_values: list = field(default_factory=list) + units: list = field(default_factory=list) + cb_formats: list = field(default_factory=list) + colormaps: list = field(default_factory=list) + disc_colormaps: list = field(default_factory=list) + linestyle: list = field(default_factory=list) + linewidth: list = field(default_factory=list) + colors: list = field(default_factory=list) + colors_default: list = field(default_factory=list) + linestyle_default: list = field(default_factory=list) + colorbar_position: tuple[float, float, float, float] = (-1.0, -1.0, -1.0, -1.0) + + # String options and values derived during initialization + difference_input: str = "" + colors_raw: str = "" # Before normalization into colors or colormaps + output_dir: str = "" + case: str = "" + fill_between_style: str = "" + colorbar_format: str = "" + fc: str = "" + inactive_color: str = "" + mask_variable: str = "" + suptitle: str = "" + colorbar_label: str = "" + slice_mode: str = "" # min keeps intersections; max keeps exact positions + xunits: str = "" + yunits: str = "" + xunit: str = "" + yunit: str = ""
+ + + +
+[docs] +@dataclass(slots=True) +class SimData: + """OPM readers, grid properties, and selected report steps for one case. + + Arrays in global cell order use the full ``nx * ny * nz`` grid. Arrays in + active-cell order follow the indexing used by INIT and UNRST properties. + + Attributes + ---------- + init, unrst, grid + OPM readers for static properties, restart properties, and grid geometry. + porv + Pore volume in global cell order; inactive cells are non-positive. + dx, dy, dz + Cell dimensions in active-cell order. + active_pv + Pore volume in active-cell order. + active_idx + Mapping from global cell indices to active-cell indices. + steps, times + Selected restart report steps and their simulation times. + ncells, nsteps + Total grid-cell and available report-step counts. + nx, ny, nz + Grid dimensions along the i, j, and k axes. + """ + + # OPM file readers and grid geometry + init: OpmFile = None + unrst: OpmRestart = None + grid: OpmGrid = None + + # Cell properties and global-to-active mapping + porv: NDArray = field(default_factory=lambda: np.array([])) + dx: NDArray = field(default_factory=lambda: np.array([])) + dy: NDArray = field(default_factory=lambda: np.array([])) + dz: NDArray = field(default_factory=lambda: np.array([])) + active_pv: NDArray = field(default_factory=lambda: np.array([])) + active_idx: NDArray = field(default_factory=lambda: np.array([])) + + # Selected report steps and simulation times + steps: list = field(default_factory=list) + times: list = field(default_factory=list) + + # Grid and report-step dimensions + ncells: int = 0 + nsteps: int = 0 + nx: int = 0 + ny: int = 0 + nz: int = 0
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/core/plopm.html b/docs/_modules/plopm/core/plopm.html new file mode 100644 index 0000000..8384aab --- /dev/null +++ b/docs/_modules/plopm/core/plopm.html @@ -0,0 +1,1986 @@ + + + + + + + + + + plopm.core.plopm — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.core.plopm

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=C0302,R1702,W0123,W1401,R0912,R0914,R0915
+
+"""Command-line entry point and top-level workflow coordination for plopm.
+
+plopm supports three output workflows for OPM Flow simulation results:
+
+* One-dimensional plots and CSV files can be generated from summary vectors,
+  tabulated functions, grid-cell sensors, layers, histograms, and distances.
+* Two-dimensional PNG figures and GIF animations can be generated for selected
+  grid slices, with optional aggregation, masking, differences, wells, and faults.
+* VTK time series can be generated by combining OPM grid geometry with selected
+  INIT and UNRST properties.
+
+This module parses and validates command-line arguments, builds the runtime
+configuration, selects the appropriate workflow, and reports the generated
+files. Data reading, numerical processing, plotting, and file generation are
+implemented in the utility modules.
+"""
+
+import argparse
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+
+from plopm.utils.initialization import (
+    build_config,
+    init_maps,
+    init_summary,
+    is_summary,
+)
+from plopm.utils.terminal import (
+    PlopmHelpFormatter,
+    cli_error_value,
+    plopm_error,
+    plopm_info,
+    plopm_name,
+    plopm_success,
+    plopm_tip,
+    warn_deprecated_options,
+)
+from plopm.utils.write_oned import make_plots
+from plopm.utils.write_twod import make_maps
+from plopm.utils.write_vtk import make_vtks
+
+
+
+[docs] +def main(argv: list[str] | None = None) -> None: + """Run the plopm command-line workflow. + + The function parses and validates CLI arguments, builds the shared + configuration, and dispatches VTK export, one-dimensional plotting, or + two-dimensional map generation. It reports the generated files after the + selected workflow completes. + + Parameters + ---------- + argv : list[str], optional + Arguments to parse instead of ``sys.argv[1:]``. This is primarily used + by tests and programmatic callers. + + """ + cmdargs = _load_parser(argv) + _check_cmdargs(cmdargs) + cfg = build_config(cmdargs) + if cfg.vtk: + plopm_info("processing, please wait...") + generated_files = make_vtks( + cmdargs.flow_path, + cfg.cases, + cfg.output_dir, + cfg.filename, + cfg.restart, + cfg.variables, + cfg.vtk_format, + cfg.vtk_names, + cfg.gif, + cfg.vtk, + cfg.filters, + cfg.scale_factor, + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters, + ) + else: + if shutil.which("latex") is None: + plopm_tip( + "install LaTeX for improved fonts and text formatting; " + f"see the {plopm_name()} documentation for installation instructions." + ) + if is_summary(cfg): + plopm_info("processing, please wait...") + init_summary(cfg) + generated_files = make_plots(cfg) + else: + plopm_info("processing, please wait...") + init_maps(cfg) + generated_files = make_maps(cfg) + plopm_success(cfg.output_dir, generated_files)
+ + + +def _load_parser(argv: list[str] | None = None) -> argparse.Namespace: + """Create the CLI parser and parse plopm arguments. + + Parameters + ---------- + argv : list[str], optional + Arguments to parse instead of ``sys.argv[1:]``. + + Returns + ------- + argparse.Namespace + Parsed command-line arguments. + + """ + + parser = argparse.ArgumentParser( + formatter_class=PlopmHelpFormatter, + description=( + "plopm: Simplified and flexible Python tool for quick visualization " + "of OPM Flow geological models. See the online documentation for " + "examples and detailed option descriptions: " + "https://cssr-tools.github.io/plopm/introduction.html#option-reference" + ), + ) + + # ------------------------------------------------------------------ + # Input and data selection + # ------------------------------------------------------------------ + + inputs = parser.add_argument_group("Input and data selection") + + inputs.add_argument( + "-i", + "--input", + type=str.strip, + default="SPE11B", + help=( + "Base name or full path of the input. Separate multiple inputs " + 'with spaces, e.g. "SPE11B /home/user/SPE11B_TUNED"' + ), + ) + inputs.add_argument( + "-v", + "--variable", + type=str.strip, + default="poro,permx,permz,porv,fipnum,satnum", + help=( + "Variable specification(s) to plot, including standard variables, " + "special variables, and expressions. Separate variables with commas" + ), + ) + inputs.add_argument( + "-r", + "--restart", + type=str.strip, + default="-1", + help=( + "Restart step(s): a single step, comma-separated steps, or " + 'start:end[:step], e.g. "-1", "0,3,10", or "5:505:250"' + ), + ) + inputs.add_argument( + "-cc", + "--csv-columns", + "-csv", + "--csv", + type=str.strip, + default="", + help=( + "CSV column indices starting at 1. Use t,value for time series or " + "x,y,value for spatial maps; separate inputs with semicolons" + ), + ) + inputs.add_argument( + "-fp", + "--flow-path", + "-p", + "--path", + type=str.strip, + default="flow", + help="Path or command for the Flow executable used for VTK grid generation", + ) + + # ------------------------------------------------------------------ + # Output options + # ------------------------------------------------------------------ + + output = parser.add_argument_group("Output options") + + output.add_argument( + "-m", + "--format", + "--mode", + type=str.strip, + choices=["png", "gif", "csv", "vtk"], + default="png", + help="Output format", + ) + output.add_argument( + "-o", + "--output-dir", + "--output", + type=str.strip, + default=".", + help="Base name or full path of the output directory", + ) + output.add_argument( + "-fn", + "--filename", + "-save", + "--save", + type=str.strip, + default="", + help="Output file name", + ) + + # ------------------------------------------------------------------ + # Spatial and temporal selection + # ------------------------------------------------------------------ + + selection = parser.add_argument_group("Spatial and temporal selection") + + selection.add_argument( + "-s", + "--slice", + "--slide", + type=str.strip, + default=",1,", + help=( + "Spatial selection in i,j,k form, e.g. " + '"10,," for a plane, ",,5:10" for a range, ' + '":,5,7" for a line, or "2,4,9" for a cell over time' + ), + ) + selection.add_argument( + "-tu", + "--time-units", + "-tunits", + "--tunits", + type=str.strip, + choices=["s", "m", "h", "d", "w", "y", "dates", "empty", "tstep"], + default="d", + help="Summary-plot x-axis time units", + ) + selection.add_argument( + "-dist", + "--distance", + "-distance", + type=str.strip, + choices=["min,sensor", "max,sensor", "min,border", "max,border", ""], + default="", + help="Compute the minimum or maximum distance to a sensor or lateral border", + ) + + # ------------------------------------------------------------------ + # Filtering, masking, and thresholds + # ------------------------------------------------------------------ + + filtering = parser.add_argument_group("Filtering, masking, and thresholds") + + filtering.add_argument( + "-flt", + "--filters", + "-filter", + type=str.strip, + default="", + help=( + "Cell-selection conditions. Join conditions for one input with '&' " + "and separate filters for different inputs with commas" + ), + ) + filtering.add_argument( + "-vmin", + "--min-threshold", + "--vmin", + type=str.strip, + default="", + help="Minimum threshold used to remove variable values", + ) + filtering.add_argument( + "-vmax", + "--max-threshold", + "--vmax", + type=str.strip, + default="", + help="Maximum threshold used to remove variable values", + ) + filtering.add_argument( + "-mv", + "--mask-variable", + "-mask", + "--mask", + type=str.strip, + default="", + help="Static variable used as the background of a 2D map", + ) + filtering.add_argument( + "-mt", + "--mask-threshold", + "-maskthr", + "--maskthr", + type=str.strip, + default="1e-3", + help="Threshold applied to the mask variable", + ) + + # ------------------------------------------------------------------ + # Computation and data transformation + # ------------------------------------------------------------------ + + computation = parser.add_argument_group("Computation and data transformation") + + computation.add_argument( + "-agg", + "--aggregation", + "-how", + "--how", + type=str.strip, + default="", + help=( + "Aggregation or selection method for 2D slices and projections: " + "min, max, sum, mean, pvmean, harmonic, arithmetic, first, or last" + ), + ) + computation.add_argument( + "-sf", + "--scale-factor", + "-a", + "--adjust", + type=str.strip, + default="1", + help=( + "Multiplicative scaling factor applied to variable values, " + "e.g. 1e-9 to display mass in Mt" + ), + ) + computation.add_argument( + "-di", + "--difference-input", + "-diff", + "--diff", + type=str.strip, + default="", + help="Base name or full path of the input model to subtract", + ) + computation.add_argument( + "-sc", + "--stress-coefficient", + "-stress", + "--stress", + type=str.strip, + default="0.134", + help=( + "Stress coefficient used to compute pressure limits for " + "limipres, overpres, and objepres" + ), + ) + computation.add_argument( + "-dg", + "--dual-grid", + "-dual", + "--dual", + type=str.strip, + default="0", + help="Enable dual-grid processing using 0 or 1", + ) + + # ------------------------------------------------------------------ + # Plot types and statistical representation + # ------------------------------------------------------------------ + + plot_types = parser.add_argument_group("Plot types and statistical representation") + + plot_types.add_argument( + "-hist", + "--histogram", + "-histogram", + type=str.strip, + default="", + help=( + "Histogram bins and optional distribution, e.g. " + '"20", "20,norm", or "20,lognorm"' + ), + ) + plot_types.add_argument( + "-ens", + "--ensemble", + "-ensemble", + type=str.strip, + choices=["0", "1", "2", "3"], + default="0", + help=( + "Ensemble plotting mode: 0 disables it, 1 plots mean and error " + "bands, 2 plots minimum, mean, and maximum, and 3 plots both" + ), + ) + plot_types.add_argument( + "-fb", + "--fill-between-style", + "-bandprop", + "--bandprop", + type=str.strip, + default="", + help="Fill colors and alpha values for ensemble error bands", + ) + plot_types.add_argument( + "-sp", + "--step-plot", + "-step", + "--step", + type=str.strip, + choices=["0", "1"], + default="0", + help="Use ax.step instead of ax.plot", + ) + + # ------------------------------------------------------------------ + # Figure and subplot layout + # ------------------------------------------------------------------ + + layout = parser.add_argument_group("Figure and subplot layout") + + layout.add_argument( + "-fs", + "--figsize", + "-d", + "--dimensions", + type=str.strip, + default="7,5", + help='Figure width and height in inches, e.g. "8,16"', + ) + layout.add_argument( + "-sg", + "--subplot-grid", + "-subfigs", + "--subfigs", + type=str.strip, + default="", + help='Number of subplot rows and columns, e.g. "2,2"', + ) + layout.add_argument( + "-cbp", + "--colorbar-position", + "-cbsfax", + "--cbsfax", + type=str.strip, + default="0.2,0.01,0.6,0.02", + help=( + "Global colorbar position and size as left,bottom,width,height; " + "use 'empty' to remove it" + ), + ) + layout.add_argument( + "-rdl", + "--remove-duplicate-labels", + "-delax", + "--delax", + type=str.strip, + choices=["0", "1"], + default="0", + help="Remove duplicated axis labels in subplot layouts", + ) + + # ------------------------------------------------------------------ + # Titles, labels, and legends + # ------------------------------------------------------------------ + + text = parser.add_argument_group("Titles, labels, and legends") + + text.add_argument( + "-t", + "--title", + type=str.strip, + default="0", + help="Figure title; separate titles for multiple plots with two spaces", + ) + text.add_argument( + "-st", + "--suptitle", + "-suptitle", + type=str.strip, + default="", + help="Title for a group of subplots; use 0 to remove it", + ) + text.add_argument( + "-xl", + "--xlabel", + "-xlabel", + type=str.strip, + default="", + help="X-axis label; separate labels for multiple plots with two spaces", + ) + text.add_argument( + "-yl", + "--ylabel", + "-ylabel", + type=str.strip, + default="", + help="Y-axis label; separate labels for multiple plots with two spaces", + ) + text.add_argument( + "-cbl", + "--colorbar-label", + "-clabel", + "--clabel", + type=str.strip, + default="", + help="Colorbar label; separate labels for multiple plots with two spaces", + ) + text.add_argument( + "-llb", + "--legend-labels", + "-labels", + "--labels", + type=str.strip, + default="", + help="Summary-plot legend labels separated by two spaces", + ) + text.add_argument( + "-ll", + "--legend-location", + "-loc", + "--loc", + type=str.strip, + default="best", + help="Legend location passed to matplotlib; use 'empty' to remove it", + ) + text.add_argument( + "-hide", + "--hide-map-elements", + "-remove", + "--remove", + type=str.strip, + default="0,0,0,0", + help=( + "Hide the left axis, bottom axis, colorbar, and title using four " + "comma-separated values of 0 or 1" + ), + ) + + # ------------------------------------------------------------------ + # Axes, coordinates, and formatting + # ------------------------------------------------------------------ + + axes = parser.add_argument_group("Axes, coordinates, and formatting") + + axes.add_argument( + "-x", + "--xlim", + type=str.strip, + default="", + help='X-axis limits in display order, e.g. "[-100,200]"', + ) + axes.add_argument( + "-y", + "--ylim", + type=str.strip, + default="", + help='Y-axis limits in display order, e.g. "[0,300]"', + ) + axes.add_argument( + "-xu", + "--xunits", + "-xunits", + type=str.strip, + choices=["mm", "cm", "m", "km"], + default="m", + help="Spatial-map x-axis units", + ) + axes.add_argument( + "-yu", + "--yunits", + "-yunits", + type=str.strip, + choices=["mm", "cm", "m", "km"], + default="m", + help="Spatial-map y-axis units", + ) + axes.add_argument( + "-asp", + "--equal-aspect", + "-z", + "--scale", + type=str.strip, + choices=["0", "1"], + default="1", + help="Scale the axes equally in 2D maps", + ) + axes.add_argument( + "-rot", + "--rotation", + "-rotate", + "--rotate", + type=str.strip, + default="0", + help="Grid rotation angle in degrees for 2D maps", + ) + axes.add_argument( + "-tr", + "--translation", + "-translate", + "--translate", + type=str.strip, + default="[0,0]", + help='Grid translation in the x and y directions, e.g. "[100,-50]"', + ) + axes.add_argument( + "-xlog", + "--xlog", + type=str.strip, + default="0", + help="Enable the logarithmic x-axis using 0 or 1", + ) + axes.add_argument( + "-ylog", + "--ylog", + type=str.strip, + default="0", + help="Enable the logarithmic y-axis using 0 or 1", + ) + axes.add_argument( + "-xf", + "--xformat", + "-xformat", + type=str.strip, + default="", + help='X-axis number format, e.g. ".2e"', + ) + axes.add_argument( + "-yf", + "--yformat", + "-yformat", + type=str.strip, + default="", + help='Y-axis number format, e.g. ".1f"', + ) + axes.add_argument( + "-xnt", + "--xtick-count", + "-xlnum", + "--xlnum", + type=str.strip, + default="5", + help="Number of x-axis ticks", + ) + axes.add_argument( + "-ynt", + "--ytick-count", + "-ylnum", + "--ylnum", + type=str.strip, + default="5", + help="Number of y-axis ticks", + ) + + # ------------------------------------------------------------------ + # Color scales and styling + # ------------------------------------------------------------------ + + styling = parser.add_argument_group("Color scales and styling") + + styling.add_argument( + "-c", + "--colors", + type=str.strip, + default="", + help='Colormap or summary-plot colors, e.g. "jet" or "b,r"', + ) + styling.add_argument( + "-cl", + "--clim", + "-b", + "--bounds", + type=str.strip, + default="", + help='Color-scale limits in display order, e.g. "[-0.1,11]"', + ) + styling.add_argument( + "-clog", + "--color-log", + "-log", + "--log", + type=str.strip, + default="0", + help="Enable logarithmic color scaling using 0 or 1", + ) + styling.add_argument( + "-clt", + "--color-log-ticks", + "-clogthks", + "--clogthks", + type=str.strip, + default="", + help='Tick values for logarithmic color scales, e.g. "[1,10,100]"', + ) + styling.add_argument( + "-gr", + "--global-range", + "-global", + "--global", + type=str.strip, + choices=["0", "1"], + default="0", + help="Use the current slice range or whole-model range for color scaling", + ) + styling.add_argument( + "-cbf", + "--colorbar-format", + "-cformat", + "--cformat", + type=str.strip, + default="", + help='Colorbar number format, e.g. ".2f"', + ) + styling.add_argument( + "-cbn", + "--colorbar-tick-count", + "-cnum", + "--cnum", + type=str.strip, + default="", + help="Number of colorbar ticks", + ) + styling.add_argument( + "-cbt", + "--colorbar-ticks", + "-cticks", + "--cticks", + type=str.strip, + default="", + help='Custom colorbar tick labels, e.g. "[A,B,C]"', + ) + styling.add_argument( + "-lw", + "--linewidth", + "--lw", + type=str.strip, + default="", + help="Line widths separated by commas", + ) + styling.add_argument( + "-ls", + "--linestyle", + "-e", + type=str.strip, + default="", + help='Line styles separated by commas, e.g. "solid,dotted"', + ) + styling.add_argument( + "-ag", + "--axis-grid", + "-axgrid", + "--axgrid", + type=str.strip, + choices=["0", "1"], + default="1", + help="Display the summary-plot axis grid", + ) + styling.add_argument( + "-fc", + "--facecolor", + "-facecolor", + type=str.strip, + default="w", + help="Color outside the spatial map", + ) + styling.add_argument( + "-ic", + "--inactive-color", + "-ncolor", + "--ncolor", + type=str.strip, + default="w", + help="Color for inactive cells in 2D maps", + ) + styling.add_argument( + "-ge", + "--grid-edges", + "-grid", + "--grid", + type=str.strip, + default="", + help="pcolormesh edge color and line width separated by a comma", + ) + styling.add_argument( + "-fz", + "--fontsize", + "-f", + "--size", + type=str.strip, + default="12", + help="Font size", + ) + styling.add_argument( + "-dpi", + "--dpi", + type=str.strip, + default="500", + help="Figure resolution in dots per inch", + ) + + # ------------------------------------------------------------------ + # VTK output + # ------------------------------------------------------------------ + + vtk = parser.add_argument_group("VTK output") + + vtk.add_argument( + "-vf", + "--vtk-format", + "-vtkformat", + "--vtkformat", + type=str.strip, + default="Float64", + help="VTK data type for each variable, separated by commas", + ) + vtk.add_argument( + "-vn", + "--vtk-names", + "-vtknames", + "--vtknames", + type=str.strip, + default="", + help="Custom VTK variable names separated by commas", + ) + + # ------------------------------------------------------------------ + # GIF output + # ------------------------------------------------------------------ + + gif = parser.add_argument_group("GIF output") + + gif.add_argument( + "-gi", + "--gif-interval", + "-interval", + "--interval", + type=str.strip, + default="1000", + help="GIF frame interval in milliseconds", + ) + gif.add_argument( + "-gl", + "--gif-loop", + "-loop", + "--loop", + type=str.strip, + default="0", + help="Loop GIF animations indefinitely using 0 or 1", + ) + + # ------------------------------------------------------------------ + # Information and diagnostics + # ------------------------------------------------------------------ + + diagnostics = parser.add_argument_group("Information and diagnostics") + + diagnostics.add_argument( + "-lv", + "--list-variables", + "-printv", + "--printv", + type=str.strip, + choices=["0", "1"], + default="0", + help="Print the available variables", + ) + + parsed_argv = sys.argv[1:] if argv is None else argv + + warn_deprecated_options(parsed_argv) + + return parser.parse_args(parsed_argv) + + +def _check_cmdargs(cmdargs: argparse.Namespace) -> None: + """Validate command-line values and option combinations. + + The function checks value syntax, accepted choices, mutually exclusive + operations, mode-specific options, and availability of OPM Flow for VTK + generation. + + Parameters + ---------- + cmdargs : argparse.Namespace + Parsed arguments returned by :func:`_load_parser`. + + Raises + ------ + SystemExit + If a value is invalid or incompatible options are requested. + + """ + + mode = cmdargs.format + vtk_mode = mode == "vtk" + gif_mode = mode == "gif" + number = r"[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?" + positive_integer = r"[1-9]\d*" + non_negative_integer = r"\d+" + + if not cmdargs.input: + plopm_error(f"the input {cli_error_value('-i')} cannot be empty.") + if not cmdargs.output_dir: + plopm_error(f"the output folder {cli_error_value('-o')} cannot be empty.") + if not cmdargs.variable: + plopm_error(f"the variable {cli_error_value('-v')} cannot be empty.") + + positive_number_options = [ + ("-fz", "fontsize"), + ("-dpi", "dpi"), + ("-xnt", "xtick_count"), + ("-ynt", "ytick_count"), + ("-mt", "mask_threshold"), + ("-gi", "gif_interval"), + ] + for option, name in positive_number_options: + raw_value = getattr(cmdargs, name) + value = _parse_number(option, raw_value) + if value <= 0: + plopm_error( + f"expected a positive number, not " + f"{cli_error_value(f'{option} {raw_value}')}." + ) + + number_options = [ + ("-sc", "stress_coefficient"), + ("-rot", "rotation"), + ] + for option, name in number_options: + _parse_number(option, getattr(cmdargs, name)) + + __parse_number_list("-sf", cmdargs.scale_factor) + + optional_number_options = [ + ("-vmin", "min_threshold"), + ("-vmax", "max_threshold"), + ] + for option, name in optional_number_options: + value = getattr(cmdargs, name) + if value: + _parse_number(option, value) + + if ( + cmdargs.min_threshold + and cmdargs.max_threshold + and float(cmdargs.min_threshold) > float(cmdargs.max_threshold) + ): + plopm_error( + f"the minimum threshold " + f"{cli_error_value(f'-vmin {cmdargs.min_threshold}')} must not be " + f"greater than the maximum threshold " + f"{cli_error_value(f'-vmax {cmdargs.max_threshold}')}." + ) + + colorbar_tick_numbers = cmdargs.colorbar_tick_count + if colorbar_tick_numbers: + cnum_entries = colorbar_tick_numbers.split(",") + if any(not re.fullmatch(positive_integer, entry) for entry in cnum_entries): + plopm_error( + "expected positive integers separated by commas, " + f"not {cli_error_value(f'-cbn {colorbar_tick_numbers}')}." + ) + + boolean_options = [ + ("-xlog", "xlog"), + ("-ylog", "ylog"), + ("-clog", "color_log"), + ("-dg", "dual_grid"), + ("-gl", "gif_loop"), + ] + for option, name in boolean_options: + raw_value = getattr(cmdargs, name) + values = raw_value.split(",") + if any(value not in ["0", "1"] for value in values): + plopm_error( + "expected values containing only 0 or 1, separated by commas, " + f"not {cli_error_value(f'{option} {raw_value}')}." + ) + + dimensions = __parse_number_list( + "-fs", + cmdargs.figsize, + 2, + ) + if any(value <= 0 for value in dimensions): + plopm_error( + f"figure dimensions must be positive, not " + f"{cli_error_value(f'-fs {cmdargs.figsize}')}." + ) + + translation = cmdargs.translation + if not re.fullmatch( + rf"\[\s*{number}\s*,\s*{number}\s*\]", + translation, + ): + plopm_error( + f"expected two numbers enclosed by brackets, such as " + f"{cli_error_value('-tr [10,-5]')}, not " + f"{cli_error_value(f'-tr {translation}')}." + ) + + interval_pattern = re.compile(rf"\[\s*({number})\s*,\s*({number})\s*\]") + for option, name in [ + ("-cl", "clim"), + ("-x", "xlim"), + ("-y", "ylim"), + ]: + value = getattr(cmdargs, name) + if not value: + continue + for interval_value in value.split(): + if not interval_pattern.fullmatch(interval_value): + plopm_error( + f"expected two numeric bounds enclosed by brackets, such " + f"as {cli_error_value(f'{option} [0,10]')}, not " + f"{cli_error_value(f'{option} {interval_value}')}." + ) + + aggregation_methods = cmdargs.aggregation + if aggregation_methods: + valid_aggregation_methods = [ + "min", + "max", + "sum", + "mean", + "pvmean", + "harmonic", + "arithmetic", + "first", + "last", + ] + method_entries = aggregation_methods.split(",") + if any(method not in valid_aggregation_methods for method in method_entries): + plopm_error( + f"expected aggregation methods from " + f"{', '.join(valid_aggregation_methods)}, not " + f"{cli_error_value(f'-agg {aggregation_methods}')}." + ) + + slice_value = cmdargs.slice + slices = slice_value.split() + slice_entry_pattern = re.compile( + rf"(?:{positive_integer}|" rf"{positive_integer}:{positive_integer}|:)?" + ) + if not slices: + plopm_error(f"the slice selection {cli_error_value('-s')} cannot be empty.") + + slice_entries: list[list[str]] = [] + for selection in slices: + entries = selection.split(",") + if len(entries) != 3 or any( + not slice_entry_pattern.fullmatch(entry) for entry in entries + ): + plopm_error( + f"expected three i,j,k entries separated by commas, using " + f"positive indices, ':', or ranges, not " + f"{cli_error_value(f'-s {selection}')}." + ) + if all(not entry for entry in entries): + plopm_error( + f"at least one slice entry must be provided with " + f"{cli_error_value(f'-s {selection}')}." + ) + colon_entries = 0 + for entry in entries: + if ":" not in entry: + continue + colon_entries += 1 + if entry != ":": + start, end = (int(index) for index in entry.split(":")) + if start > end: + plopm_error( + f"the end of range {cli_error_value(entry)} in " + f"{cli_error_value(f'-s {selection}')} must not be smaller " + "than the start." + ) + if colon_entries > 1: + plopm_error( + f"only one slice direction in " + f"{cli_error_value(f'-s {selection}')} can contain ':' or an index " + "range." + ) + slice_entries.append(entries) + + restart = cmdargs.restart + restart_pattern = re.compile( + rf"(?:-1|" + rf"{non_negative_integer}(?:,{non_negative_integer})*|" + rf"{non_negative_integer}:{non_negative_integer}" + rf"(?::{positive_integer})?)" + ) + if not restart_pattern.fullmatch(restart): + plopm_error( + f"expected '-1', non-negative restart indices separated by " + f"commas, or 'start:end[:step]', not " + f"{cli_error_value(f'-r {restart}')}." + ) + + if ":" in restart: + restart_range = [int(value) for value in restart.split(":")] + if restart_range[0] > restart_range[1]: + plopm_error( + f"the end of restart range {cli_error_value(f'-r {restart}')} must " + "not be smaller than the start." + ) + + list_options = [ + ("-c", "colors"), + ("-ls", "linestyle"), + ] + for option, name in list_options: + value = getattr(cmdargs, name) + if value and any(not entry for entry in value.split(",")): + plopm_error( + f"entries in {cli_error_value(f'{option} {value}')} cannot be empty." + ) + + line_widths = cmdargs.linewidth + if line_widths: + width_values = __parse_number_list("-lw", line_widths) + if any(width <= 0 for width in width_values): + plopm_error( + f"line widths must be positive, not " + f"{cli_error_value(f'-lw {line_widths}')}." + ) + + remove = cmdargs.hide_map_elements + remove_entries = remove.split(",") + if len(remove_entries) != 4 or any( + entry not in ["0", "1"] for entry in remove_entries + ): + plopm_error( + f"expected four values containing only 0 or 1, not " + f"{cli_error_value(f'-hide {remove}')}." + ) + + subfigs = cmdargs.subplot_grid + if subfigs: + subfig_entries = subfigs.split(",") + if len(subfig_entries) != 2 or any( + not re.fullmatch(positive_integer, entry) for entry in subfig_entries + ): + plopm_error( + f"expected two positive integers separated by a comma, such " + f"as {cli_error_value('-sg 2,2')}, not " + f"{cli_error_value(f'-sg {subfigs}')}." + ) + + colorbar_axis = cmdargs.colorbar_position + if colorbar_axis != "empty": + colorbar_axis_values = __parse_number_list( + "-cbp", + colorbar_axis, + 4, + ) + if colorbar_axis_values[0] < 0 or colorbar_axis_values[1] < 0: + plopm_error( + f"the left and bottom positions in " + f"{cli_error_value(f'-cbp {colorbar_axis}')} cannot be negative." + ) + if colorbar_axis_values[2] <= 0 or colorbar_axis_values[3] <= 0: + plopm_error( + f"the width and height in " + f"{cli_error_value(f'-cbp {colorbar_axis}')} must be positive." + ) + + grid = cmdargs.grid_edges + if grid: + grid_entries = grid.split(",") + if len(grid_entries) != 2 or not grid_entries[0] or not grid_entries[1]: + plopm_error( + f"expected a color and line width separated by a comma, not " + f"{cli_error_value(f'-ge {grid}')}." + ) + if _parse_number("-ge", grid_entries[1]) < 0: + plopm_error( + f"the line width in {cli_error_value(f'-ge {grid}')} cannot be " + "negative." + ) + + csv_columns = cmdargs.csv_columns + if csv_columns: + csv_specifications = csv_columns.split(";") + for specification in csv_specifications: + if not specification: + continue + column_entries = specification.split(",") + if len(column_entries) not in [2, 3] or any( + not re.fullmatch(positive_integer, entry) for entry in column_entries + ): + plopm_error( + f"each non-empty specification in " + f"{cli_error_value(f'-cc {csv_columns}')} must contain two " + "column indices for a time series or three column indices " + "for a spatial map." + ) + if len(set(column_entries)) != len(column_entries): + plopm_error( + f"column indices within each specification in " + f"{cli_error_value(f'-cc {csv_columns}')} must be different." + ) + + histogram = cmdargs.histogram + if histogram: + histogram_specifications = histogram.split() + for specification in histogram_specifications: + histogram_entries = specification.split(",") + if len(histogram_entries) not in [1, 2]: + plopm_error( + f"expected 'bins', 'bins,norm', or 'bins,lognorm', not " + f"{cli_error_value(f'-hist {specification}')}." + ) + if not re.fullmatch( + positive_integer, + histogram_entries[0], + ): + plopm_error( + f"the number of bins in " + f"{cli_error_value(f'-hist {specification}')} must be a positive " + "integer." + ) + if len(histogram_entries) == 2 and histogram_entries[1] not in [ + "norm", + "lognorm", + ]: + plopm_error( + f"the distribution in " + f"{cli_error_value(f'-hist {specification}')} must be 'norm' or " + "'lognorm'." + ) + + band_properties = cmdargs.fill_between_style + if band_properties: + band_entries = band_properties.split(",") + if len(band_entries) % 2 != 0 or any(not color for color in band_entries[::2]): + plopm_error( + f"expected color and alpha pairs, not " + f"{cli_error_value(f'-fb {band_properties}')}." + ) + try: + alpha_values = [float(alpha) for alpha in band_entries[1::2]] + except ValueError: + alpha_values = [] + if not alpha_values or any(alpha < 0 or alpha > 1 for alpha in alpha_values): + plopm_error( + f"alpha values in {cli_error_value(f'-fb {band_properties}')} must " + "be between 0 and 1." + ) + if cmdargs.ensemble not in ["1", "3"]: + plopm_error( + f"{cli_error_value('-fb')} can only be used with " + f"{cli_error_value('-ens 1')} or {cli_error_value('-ens 3')}." + ) + + log_values = cmdargs.color_log.split(",") + + if cmdargs.color_log_ticks and "1" not in log_values: + plopm_error( + f"{cli_error_value('-clt')} requires at least one logarithmic color " + f"scale enabled with {cli_error_value('-clog')}." + ) + + if cmdargs.mask_threshold != "1e-3" and not cmdargs.mask_variable: + plopm_error( + f"{cli_error_value('-mt')} can only be changed when " + f"{cli_error_value('-mv')} is used." + ) + + if ( + cmdargs.distance + and "sensor" in cmdargs.distance + and any( + any(not re.fullmatch(positive_integer, entry) for entry in entries) + for entries in slice_entries + ) + ): + plopm_error( + f"a sensor distance requires each location provided with " + f"{cli_error_value('-s')} to contain three positive indices." + ) + + vtk_names = cmdargs.vtk_names + if vtk_names: + vtk_name_entries = vtk_names.split(",") + if any(not name for name in vtk_name_entries): + plopm_error( + f"VTK variable names in {cli_error_value(f'-vn {vtk_names}')} " + "cannot be empty." + ) + + valid_vtk_formats = [ + "Float64", + "Float32", + "Float16", + "Int64", + "UInt64", + "Int32", + "UInt32", + "Int16", + "UInt16", + "Int8", + "UInt8", + ] + vtk_formats = cmdargs.vtk_format.split(",") + if any(vtk_format not in valid_vtk_formats for vtk_format in vtk_formats): + plopm_error( + f"expected VTK formats from {', '.join(valid_vtk_formats)}, not " + f"{cli_error_value(f'-vf {cmdargs.vtk_format}')}." + ) + + vtk_options = { + "-fp": ("flow_path", "flow"), + "-vf": ("vtk_format", "Float64"), + "-vn": ("vtk_names", ""), + } + if not vtk_mode: + invalid_options = [ + option + for option, (name, default) in vtk_options.items() + if getattr(cmdargs, name) != default + ] + if invalid_options: + formatted_options = ", ".join( + cli_error_value(option) for option in invalid_options + ) + plopm_error( + f"{formatted_options} can only be used with " + f"{cli_error_value('-m vtk')}, not {cli_error_value(f'-m {mode}')}." + ) + else: + try: + flow_arguments = shlex.split(cmdargs.flow_path) + except ValueError: + flow_arguments = [] + + if not flow_arguments: + plopm_error( + f"the OPM Flow command " + f"{cli_error_value(f'-fp {cmdargs.flow_path}')} cannot be empty." + ) + + try: + flow_result = subprocess.run( + [*flow_arguments, "-h"], + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, + check=False, + ) + except OSError: + flow_result = None + + if flow_result is None or flow_result.returncode != 0: + plopm_error( + f"the OPM Flow executable " + f"{cli_error_value(f'-fp {cmdargs.flow_path}')} is not available or " + "not working." + ) + + if not gif_mode: + gif_options = { + "-gi": ("gif_interval", "1000"), + "-gl": ("gif_loop", "0"), + } + invalid_options = [ + option + for option, (name, default) in gif_options.items() + if getattr(cmdargs, name) != default + ] + if invalid_options: + formatted_options = ", ".join( + cli_error_value(option) for option in invalid_options + ) + plopm_error( + f"{formatted_options} can only be used with " + f"{cli_error_value('-m gif')}, not {cli_error_value(f'-m {mode}')}." + ) + + +def _parse_number(option: str, value: str) -> float: + """Parse one numeric command-line value. + + Parameters + ---------- + option : str + Option name used in an error message. + value : str + Value to convert. + + Returns + ------- + float + Parsed numeric value. + + Raises + ------ + SystemExit + If the value is not numeric. + + """ + try: + number = float(value) + except ValueError: + plopm_error(f"expected a number, not {cli_error_value(f'{option} {value}')}.") + return number + + +def __parse_number_list( + option: str, + value: str, + expected_length: int | None = None, +) -> list: + """Parse comma-separated numeric values. + + Parameters + ---------- + option : str + Option name used in an error message. + value : str + Comma-separated values to convert. + expected_length : int, optional + Required number of values. + + Returns + ------- + list[float] + Parsed numeric values. + + Raises + ------ + SystemExit + If a value is not numeric or the length is invalid. + + """ + entries = value.split(",") + if expected_length is not None and len(entries) != expected_length: + plopm_error( + f"expected {expected_length} numbers separated by commas, " + f"not {cli_error_value(f'{option} {value}')}." + ) + try: + numbers = [float(entry) for entry in entries] + except ValueError: + plopm_error( + "expected numbers separated by commas, " + f"not {cli_error_value(f'{option} {value}')}." + ) + return numbers +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/initialization.html b/docs/_modules/plopm/utils/initialization.html new file mode 100644 index 0000000..5de24c6 --- /dev/null +++ b/docs/_modules/plopm/utils/initialization.html @@ -0,0 +1,1385 @@ + + + + + + + + + + plopm.utils.initialization — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.initialization

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=W0123,R0915,R0912,R1702,R0914,R0916
+
+"""Build and normalize configuration for plopm workflows.
+
+The module converts parsed CLI arguments into :class:`PlopmConfig`, discovers
+simulation cases, normalizes per-variable plotting settings, selects summary or
+spatial processing, and defines unit conversions used by the readers.
+"""
+
+import argparse
+import copy
+import os
+import shutil
+import sys
+from typing import cast
+
+import matplotlib
+import matplotlib.pyplot as plt
+from opm.io.ecl import EclFile as OpmFile
+from opm.io.ecl import ESmry as OpmSummary
+
+from plopm.config.config import PlopmConfig
+from plopm.utils.terminal import (
+    cli_current_value,
+    cli_error_value,
+    cli_info_value,
+    plopm_error,
+    plopm_info,
+)
+
+
+
+[docs] +def build_config(cmdargs: argparse.Namespace) -> PlopmConfig: + """Build a plopm configuration from parsed CLI arguments. + + The function expands case and difference-input paths, parses list-like + options, normalizes slice and restart selections, and initializes plotting + defaults shared by summary, map, and VTK workflows. + + Parameters + ---------- + cmdargs : argparse.Namespace + Command-line arguments returned by the plopm parser. + + Returns + ------- + PlopmConfig + Parsed and partially normalized runtime configuration. + + """ + + cfg = PlopmConfig() + cfg.output_dir = os.path.abspath(cmdargs.output_dir) + names = cmdargs.input.split(" ") + names = [var.split(" ") for var in names] + cfg.case_labels = names + + for name in ["gif", "csv", "png", "vtk"]: + setattr(cfg, name, cmdargs.format == name) + + cfg.difference_input = cmdargs.difference_input + cfg.ensemble = int(cmdargs.ensemble) + + if cfg.difference_input: + if cfg.difference_input[-1] in [".", "/"]: + cfg.difference_input = _find_first_case(cfg.difference_input, ".EGRID") + if names[0][0][-1] in [".", "/"]: + names[0][0] = _find_first_case(names[0][0], ".EGRID") + elif names[0][0][-1] in [".", "/"]: + folders = names[0] + names = [] + for index, folder in enumerate(folders): + if cfg.ensemble > 0 or index == 0: + names.append([]) + if cfg.vtk: + names[-1] = _find_all_cases(folder, ".DATA") + else: + names[-1] = _find_all_cases(folder, ".SMSPEC") + + cfg.cases = names + cfg.case = names[0][0] + cfg.variables = cmdargs.variable.lower().split(",") + _join_block_vars(cfg) + cfg.stress_coefficient = float(cmdargs.stress_coefficient) + + for cfg_name, cmdarg_name in [ + ("vtk_names", "vtk_names"), + ("filename", "filename"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(" ")) + + cfg.mass_vars = ["gasm", "dism", "liqm", "vapm", "co2m", "h2om"] + cfg.mass_fracs = ["xco2l", "xh2ov", "xco2v", "xh2ol"] + cfg.caprock_vars = ["limipres", "overpres", "objepres"] + for cfg_name, cmdarg_name in [ + ("filters", "filters"), + ("restart", "restart"), + ("scale_factor", "scale_factor"), + ("vtk_format", "vtk_format"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(",")) + + if cfg.restart[0] == "-1": + cfg.restart = [-1] + elif ":" in cfg.restart[0]: + cfg.rst_range = True + vals = cfg.restart[0].split(":") + if len(vals) == 3: + cfg.restart = list( + range( + int(vals[0]), + int(vals[1]) + 1, + int(vals[2]), + ) + ) + else: + cfg.restart = list( + range( + int(vals[0]), + int(vals[1]) + 1, + ) + ) + if cfg.filename[0]: + width = len(str(cfg.restart[-1])) + cfg.filename = [ + cfg.filename[0] + f"{restart_value}".zfill(width) + for restart_value in cfg.restart + ] + else: + if "," in cmdargs.restart and (cfg.png or cfg.csv): + cfg.rst_range = True + width = len(str(cfg.restart[-1])) + cfg.filename = [ + cfg.filename[0] + f"{restart_value}".zfill(width) + for restart_value in cfg.restart + ] + cfg.restart = [int(restart_value) for restart_value in cfg.restart] + for name in ["vtk_format", "scale_factor", "vtk_names"]: + if len(getattr(cfg, name)) < len(cfg.variables): + setattr( + cfg, + name, + [getattr(cfg, name)[0]] * len(cfg.variables), + ) + if not os.path.exists(cfg.output_dir): + os.makedirs(cfg.output_dir, exist_ok=True) + if cfg.vtk: + return cfg + + cfg.csv_columns = cmdargs.csv_columns.split(";") + cfg.csv_columns = [ + [int(val) if val else "" for val in var.split(",")] for var in cfg.csv_columns + ] + + allcsvs = True + for val in cfg.csv_columns: + if not val[0]: + allcsvs = False + elif len(val) == 2: + cfg.csv_column_summary = True + + if allcsvs: + cfg.variables = ["csv"] + + max_count = max(len(cfg.cases[0]), len(cfg.variables)) + if len(cfg.csv_columns) == 1 and not cfg.csv_columns[0][0]: + cfg.csv_columns = [cfg.csv_columns[0]] * (max_count + 1) + + for cfg_name, cmdarg_name in [ + ("mask_variable", "mask_variable"), + ("linewidth", "linewidth"), + ("linestyle", "linestyle"), + ("inactive_color", "inactive_color"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).lower()) + + for cfg_name, cmdarg_name in [ + ("fontsize", "fontsize"), + ("mask_threshold", "mask_threshold"), + ("gif_interval", "gif_interval"), + ]: + setattr(cfg, cfg_name, float(getattr(cmdargs, cmdarg_name))) + + for cfg_name, cmdarg_name in [ + ("colorbar_ticks", "colorbar_ticks"), + ("title", "title"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(" ")) + + for cfg_name, cmdarg_name in [ + ("clim", "clim"), + ("translation", "translation"), + ("histogram", "histogram"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(" ")) + + for cfg_name, cmdarg_name in [ + ("suptitle", "suptitle"), + ("fill_between_style", "fill_between_style"), + ("colorbar_label", "colorbar_label"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name)) + + cfg.clim = [var.split(",") for var in cfg.clim] + cfg.translation = [var.split(",") for var in cfg.translation] + cfg.colors_raw = cmdargs.colors + cfg.colorbar_format = cmdargs.colorbar_format + cfg.fc = cmdargs.facecolor + cfg.legend_labels = cmdargs.legend_labels.split(" ") + cfg.legend_labels = [var.split(" ") for var in cfg.legend_labels] + cfg.hide_map_elements = [int(val) for val in cmdargs.hide_map_elements.split(",")] + cfg.global_range = int(cmdargs.global_range) == 1 + + for cfg_name, cmdarg_name in [ + ("equal_aspect", "equal_aspect"), + ("remove_duplicate_labels", "remove_duplicate_labels"), + ("gif_loop", "gif_loop"), + ("list_variables", "list_variables"), + ("step_plot", "step_plot"), + ]: + setattr(cfg, cfg_name, int(getattr(cmdargs, cmdarg_name)) == 1) + + for cfg_name, cmdarg_name in [ + ("figsize", "figsize"), + ("distance", "distance"), + ("aggregation", "aggregation"), + ("rotation", "rotation"), + ("color_log", "color_log"), + ("legend_location", "legend_location"), + ("axis_grid", "axis_grid"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(",")) + + for cfg_name, cmdarg_name in [ + ("dpi", "dpi"), + ("time_units", "time_units"), + ("colorbar_tick_count", "colorbar_tick_count"), + ("grid_edges", "grid_edges"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(",")) + + for cfg_name, cmdarg_name in [ + ("dual_grid", "dual_grid"), + ("subplot_grid", "subplot_grid"), + ("min_threshold", "min_threshold"), + ("max_threshold", "max_threshold"), + ]: + setattr(cfg, cfg_name, getattr(cmdargs, cmdarg_name).split(",")) + + for axis_name in ["x", "y"]: + setattr( + cfg, + f"{axis_name}units", + getattr(cmdargs, f"{axis_name}units"), + ) + setattr( + cfg, + f"{axis_name}label", + getattr(cmdargs, f"{axis_name}label").split(" "), + ) + setattr( + cfg, + f"{axis_name}format", + getattr(cmdargs, f"{axis_name}format").split(","), + ) + setattr( + cfg, + f"{axis_name}tick_count", + getattr(cmdargs, f"{axis_name}tick_count").split(","), + ) + setattr( + cfg, + f"{axis_name}log", + getattr(cmdargs, f"{axis_name}log").split(","), + ) + setattr( + cfg, + f"{axis_name}lim", + getattr(cmdargs, f"{axis_name}lim").split(" "), + ) + setattr( + cfg, + f"{axis_name}lim", + [var.split(",") for var in getattr(cfg, f"{axis_name}lim")], + ) + + if cmdargs.color_log_ticks: + cfg.color_log_ticks = [ + float(val) for val in cmdargs.color_log_ticks[1:-1].split(",") + ] + + if cfg.colorbar_ticks[0]: + for index, values in enumerate(cfg.colorbar_ticks): + cfg.colorbar_ticks[index] = [val.strip() for val in values[1:-1].split(",")] + if cmdargs.colorbar_position != "empty": + cfg.colorbar_position = cast( + tuple[float, float, float, float], + tuple(map(float, cmdargs.colorbar_position.split(","))), + ) + + cfg.slice = cmdargs.slice.split(" ") + cfg.slice = [ + [val if val else [-2, -2] for val in var.split(",")] for var in cfg.slice + ] + if [-2, -2] in cfg.slice[0]: + for slice_index, var in enumerate(cfg.slice): + for value_index, val in enumerate(var): + if val[0] != -2: + if val == ":": + pass + elif ":" in val: + vals = val.split(":") + cfg.slice[slice_index][value_index] = [ + int(vals[0]) - 1, + int(vals[1]), + ] + else: + int_value = int(val) + cfg.slice[slice_index][value_index] = [int_value - 1, int_value] + elif ":" in cfg.slice[0]: + cfg.layer = True + for slice_index, var in enumerate(cfg.slice): + for value_index, val in enumerate(var): + if val != ":": + cfg.slice[slice_index][value_index] = int(val) - 1 + else: + cfg.slice[slice_index][value_index] = -1 + else: + cfg.sensor = True + for slice_index, var in enumerate(cfg.slice): + for value_index, val in enumerate(var): + cfg.slice[slice_index][value_index] = int(val) - 1 + + cfg.summary_mass = ["fwcdm", "fgipm"] + + cfg.colors_default = [ + "k", + "b", + "#ff7f0e", + "#2ca02c", + "#d62728", + "#9467bd", + "#8c564b", + "#e377c2", + "#7f7f7f", + "#bcbd22", + "#17becf", + "#1f77b4", + "r", + ] + + cfg.linestyle_default = [ + "-", + "--", + (0, (1, 1)), + "-.", + (0, (1, 10)), + (0, (1, 1)), + (5, (10, 3)), + (0, (5, 10)), + (0, (5, 5)), + (0, (5, 1)), + (0, (3, 10, 1, 10)), + (0, (3, 5, 1, 5)), + (0, (3, 1, 1, 1)), + (0, (3, 5, 1, 5, 1, 5)), + (0, (3, 10, 1, 10, 1, 10)), + (0, (3, 1, 1, 1, 1, 1)), + (0, ()), + ] + for val in cfg.variables: + for oper in ["=", "<", ">"]: + if oper in val: + cfg.discrete = False + + cfg.linewidth_values = ["1"] * len(cfg.cases[0]) + + font = {"family": "normal", "weight": "normal", "size": cfg.fontsize} + matplotlib.rc("font", **font) + plt.rcParams.update( + { + "text.usetex": shutil.which("latex") is not None, + "font.family": "monospace", + "legend.columnspacing": 0.9, + "legend.handlelength": 3.5, + "legend.fontsize": cfg.fontsize, + "lines.linewidth": 4, + "axes.titlesize": cfg.fontsize, + "axes.grid": False, + "figure.figsize": (float(cfg.figsize[0]), float(cfg.figsize[1])), + } + ) + + if len(cfg.filename) < len(cfg.variables): + cfg.filename = [cfg.filename[0]] * len(cfg.variables) + + if len(cfg.clim) < len(cfg.variables): + cfg.clim = [cfg.clim[0]] * len(cfg.variables) + + if cfg.difference_input and len(cfg.rotation) < 2: + cfg.rotation = [cfg.rotation[0]] * 2 + elif len(cfg.rotation) < len(cfg.cases[0]): + cfg.rotation = [cfg.rotation[0]] * len(cfg.cases[0]) + + if cfg.difference_input and len(cfg.translation) < 2: + cfg.translation = [cfg.translation[0]] * 2 + + if len(cfg.translation) < len(cfg.cases[0]): + cfg.translation = [cfg.translation[0]] * len(cfg.cases[0]) + + if cfg.difference_input and len(cfg.slice) < 2: + cfg.slice = [cfg.slice[0]] * 2 + + for val in [ + "aggregation", + "filters", + "colorbar_ticks", + "csv_columns", + "dual_grid", + "slice", + "title", + ]: + if len(getattr(cfg, val)) < max_count: + if val == "slice": + current = getattr(cfg, val) + setattr( + cfg, + val, + [copy.deepcopy(current[0]) for _ in range(max_count)], + ) + else: + setattr(cfg, val, [getattr(cfg, val)[0]] * max_count) + elif len(cfg.restart) > 1 and cfg.subplot_grid[0]: + if ( + len(getattr(cfg, val)) >= max(max_count, len(cfg.restart)) + and val == "title" + ): + continue + if val == "slice": + if cfg.gif and len(cfg.slice) >= len(cfg.cases[0]): + continue + current = getattr(cfg, val) + setattr( + cfg, + val, + [copy.deepcopy(current[0]) for _ in range(len(cfg.restart))], + ) + else: + setattr(cfg, val, [getattr(cfg, val)[0]] * len(cfg.restart)) + + if len(cfg.restart) > 1 and cfg.subplot_grid[0]: + cfg.filename = [cmdargs.filename] + if cfg.difference_input: + cfg.aggregation = [cfg.aggregation[0]] * 2 + cfg.filters = [cfg.filters[0]] * 2 + + for val in [ + "xformat", + "yformat", + "xlog", + "ylog", + "xlabel", + "ylabel", + "legend_labels", + "time_units", + "legend_location", + "dpi", + "ytick_count", + "xtick_count", + "filename", + "axis_grid", + "colorbar_tick_count", + "color_log", + "min_threshold", + "max_threshold", + ]: + if len(getattr(cfg, val)) < len(cfg.variables): + setattr(cfg, val, [getattr(cfg, val)[0]] * len(cfg.variables)) + + return cfg
+ + + +def _find_all_cases(folder: str, suffix: str) -> list: + """Find all simulation cases below a folder. + + Parameters + ---------- + folder : str + Folder to search recursively. + suffix : str + File suffix identifying a simulation case. + + Returns + ------- + list[str] + Sorted case paths without the identifying suffix. + + """ + folder_path = folder + if folder_path[0] != ".": + folder_path = "./" + folder_path + cases_found = [] + for root, _, files in os.walk(folder_path): + for file in files: + if file.endswith(suffix): + cases_found.append(os.path.join(root, file)[2 : -len(suffix)]) + return sorted(cases_found) + + +def _find_first_case(folder: str, suffix: str) -> str: + """Find the first simulation case below a folder. + + Parameters + ---------- + folder : str + Folder to search recursively. + suffix : str + File suffix identifying a simulation case. + + Returns + ------- + str + First case path without the suffix, or the input folder when no + matching file is found. + + """ + folder_path = folder + if folder_path[0] != ".": + folder_path = "./" + folder_path + for root, _, files in os.walk(folder_path): + for file in files: + if file.endswith(suffix): + return os.path.join(root, file)[2 : -len(suffix)] + return folder + + +def _join_block_vars(cfg: PlopmConfig) -> None: + """Rejoin comma-separated indices in block variables. + + Parameters + ---------- + cfg : PlopmConfig + Configuration whose variable expressions are updated in place. + + """ + vrs_in = cfg.variables + count = len(vrs_in) + variables = [] + index = 0 + while index < count: + if index < count - 2 and ":" in vrs_in[index] and vrs_in[index + 1].isnumeric(): + variables.append( + vrs_in[index] + "," + vrs_in[index + 1] + "," + vrs_in[index + 2] + ) + index += 3 + else: + variables.append(vrs_in[index]) + index += 1 + cfg.variables = variables + + +
+[docs] +def init_maps(cfg: PlopmConfig) -> None: + """Normalize settings used by spatial maps. + + The function selects default units, colorbar formats, and colormaps; expands + per-variable limits and formats; and initializes spatial coordinate scales. + + Parameters + ---------- + cfg : PlopmConfig + Configuration updated in place for map generation. + + """ + cfg.units = [" [-]", " [mD]", " [mD]", r" [m$^3$]", " [-]", " [-]"] + cfg.cb_formats = [".1f", ".0f", ".0f", ".2e", ".0f", ".0f"] + cfg.colormaps = ["jet", "turbo", "turbo", "terrain", "tab20b", "tab20b"] + cmdisc = [ + "Pastel1", + "Pastel2", + "Paired", + "Accent", + "Dark2", + "Set1", + "Set2", + "Set3", + "tab10", + "tab20", + "tab20b", + "tab20c", + "cet_glasbey_bw", + "cet_glasbey", + "cet_glasbey_cool", + "cet_glasbey_warm", + "cet_glasbey_dark", + "cet_glasbey_light", + "cet_glasbey_category10", + "cet_glasbey_hv", + ] + cfg.disc_colormaps = [cmap + "_r" for cmap in cmdisc] + cmdisc + if cfg.colors_raw: + cfg.colormaps = cfg.colors_raw.split(",") + elif cfg.difference_input: + cfg.colormaps = ["RdYlGn"] + elif cfg.mask_variable: + cfg.colormaps = ["RdGy_r"] + variables = cfg.variables + if variables: + first_variable = variables[0] + if first_variable in ["wells", "faults"]: + if cfg.aggregation[0]: + if cfg.aggregation[0] not in ["min", "max"]: + plopm_error( + f"Unsuported value {cli_error_value(f'-agg {cfg.aggregation[0]}')} for " + f"{cli_info_value(f'-v {first_variable}')}. Supported values are " + f"{cli_current_value('-agg min')} and {cli_current_value('-agg max')}." + ) + cfg.slice_mode = cfg.aggregation[0] + else: + cfg.slice_mode = "min" + if not cfg.colors_raw: + cfg.units = [" [-]"] + cfg.colormaps = ["nipy_spectral"] + cfg.cb_formats = [".0f"] + if ( + "num" in first_variable + and not cfg.mask_variable + and not cfg.difference_input + and not cfg.colors_raw + ): + cfg.colormaps = ["tab20"] + cfg.units = [" [-]"] + cfg.cb_formats = [".0f"] + if "index" in first_variable: + cfg.units = [" [-]"] + cfg.cb_formats = [".0f"] + if cfg.colorbar_format: + cfg.cb_formats = cfg.colorbar_format.split(",") + elif len(variables) == 1 and "num" in variables[0]: + cfg.cb_formats = [".0f"] + elif cfg.difference_input: + cfg.cb_formats = [".1e"] + nvars = len(variables) + if len(cfg.colormaps) < nvars or ( + nvars == len(cfg.cases[0]) and len(cfg.cases[0]) > 1 and not cfg.colors_raw + ): + cfg.colormaps = [cfg.colormaps[0]] * nvars + if len(cfg.xlim) < nvars: + cfg.xlim = [cfg.xlim[0]] * nvars + if len(cfg.ylim) < nvars: + cfg.ylim = [cfg.ylim[0]] * nvars + if len(cfg.cb_formats) < nvars: + cfg.cb_formats = [cfg.cb_formats[0]] * nvars + cfg.xscale, cfg.xunit = spatial_unit(cfg.xunits) + cfg.yscale, cfg.yunit = spatial_unit(cfg.yunits)
+ + + +
+[docs] +def spatial_unit(unit: str) -> tuple[float, str]: + """Get the conversion and label for a spatial unit. + + Parameters + ---------- + unit : str + Spatial-unit code. + + Returns + ------- + tuple[float, str] + Factor converting metres and the formatted unit label. + + """ + return { + "m": (1.0, " [m]"), + "km": (1e-3, " [km]"), + "cm": (1e2, " [cm]"), + "mm": (1e3, " [mm]"), + }.get(unit, (1.0, ""))
+ + + +
+[docs] +def mass_unit(mskl: float) -> str: + """Get the display unit for a mass scale factor. + + Parameters + ---------- + mskl : float + Factor applied to quantities stored in kilograms. + + Returns + ------- + str + Matplotlib-formatted mass unit, or an empty string when unknown. + + """ + return { + 1e-3: " [t]", + 1e-6: " [Kt]", + 1e-9: " [Mt]", + 1e3: " [g]", + 1e6: " [mg]", + 1: " [kg]", + }.get(mskl, "")
+ + + +
+[docs] +def is_summary(cfg: PlopmConfig) -> bool: + """Determine whether the request uses one-dimensional output. + + The decision considers explicit series options, special tabulated + properties, summary-vector availability, and requests to list variables. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration and primary case path. + + Returns + ------- + bool + ``True`` when the request should use the summary plotting workflow. + + """ + name = cfg.case + variables = cfg.variables + first_variable = variables[0] if variables else "" + ntot = 0 + if cfg.list_variables: + for ext in ["INIT", "UNRST"]: + file = f"{name}.{ext}" + if os.path.isfile(file): + reader = OpmFile(file) + keys = [ + var[0] + for var in reader.arrays + if var[0] + not in ["INTEHEAD", "LOGIHEAD", "DOUBHEAD", "TABDIMS", "TAB"] + ] + if ext == "UNRST": + ntot = reader.count("PRESSURE") + plopm_info( + f"the available {cli_info_value('-v')} variables for " + f"{cli_info_value(file)} are:" + ) + print(keys) + if ext == "UNRST": + plopm_info( + f"the available {cli_info_value('-r')} restarts for " + f"{cli_info_value(file)} are:" + ) + print(list(range(ntot))) + if ( + cfg.sensor + or cfg.layer + or cfg.distance[0] + or cfg.histogram[0] + or cfg.csv_column_summary + ): + return True + if ( + first_variable[:3] in ["krw", "krg"] + or first_variable[:4] in ["krow", "krog", "pcow", "pcog", "pcwg"] + or first_variable[:6] == "pcfact" + or ( + first_variable[:8] == "permfact" + and cfg.slice == [[[-2, -2], [0, 1], [-2, -2]]] + ) + ): + return True + smspec_file = f"{name}.SMSPEC" + if os.path.isfile(smspec_file): + summary = OpmSummary(smspec_file).keys() + if cfg.list_variables: + plopm_info( + f"the available {cli_info_value('-v')} variables for " + f"{cli_info_value(smspec_file)} are:" + ) + print(summary) + sys.exit(0) + smass = cfg.summary_mass + for name_v in variables: + base = name_v.split(" ")[0].upper() + if base in summary or base.lower() in smass: + return True + if cfg.list_variables: + sys.exit(0) + return False
+ + + +
+[docs] +def init_summary(cfg: PlopmConfig) -> None: + """Normalize settings used by one-dimensional plots. + + Parameters + ---------- + cfg : PlopmConfig + Configuration updated in place with per-variable styles and labels. + + """ + variables = cfg.variables + nvars = len(variables) + cfg.ncolors = 1 if len(cfg.cases) < nvars else nvars + for val in ["colors_raw", "linestyle", "linewidth"]: + if getattr(cfg, val): + tmp = [var.split(",") for var in getattr(cfg, val).split(":")] + if len(tmp) < nvars: + tmp = [tmp[0]] * nvars + setattr(cfg, "colors" if val == "colors_raw" else val, tmp) + elif val == "colors_raw": + cfg.colors = [cfg.colors_default] * nvars + elif val == "linestyle": + cfg.linestyle = [cfg.linestyle_default] * nvars + else: + cfg.linewidth = [cfg.linewidth_values] * nvars + for axis_name in ["x", "y"]: + key = f"{axis_name}lim" + if len(getattr(cfg, key)) < nvars and getattr(cfg, key)[0]: + setattr(cfg, key, [getattr(cfg, key)[0]] * nvars) + if nvars == 1 and len(cfg.linewidth[0]) < len(cfg.cases[0]): + cfg.linewidth[0] = [cfg.linewidth[0][0]] * len(cfg.cases[0]) + for val in [ + "cases", + "title", + "xformat", + "yformat", + "xlog", + "ylog", + "xlabel", + "ylabel", + "legend_labels", + "time_units", + "legend_location", + "dpi", + "ytick_count", + "xtick_count", + "scale_factor", + "filename", + "axis_grid", + ]: + if len(getattr(cfg, val)) < nvars: + setattr(cfg, val, [getattr(cfg, val)[0]] * nvars)
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/mapping.html b/docs/_modules/plopm/utils/mapping.html new file mode 100644 index 0000000..7b75c5d --- /dev/null +++ b/docs/_modules/plopm/utils/mapping.html @@ -0,0 +1,1367 @@ + + + + + + + + + + plopm.utils.mapping — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.mapping

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=R1702,R0912,C0325,R0913,R0914,R0915,R0917
+
+"""Prepare slice geometry and map three-dimensional values to two dimensions.
+
+The module builds labels and coordinate meshes for xy, xz, and yz slices,
+applies optional rotation and translation, and aggregates active-cell values
+through the selected grid interval.
+"""
+
+import numpy as np
+from numpy.typing import NDArray
+
+from plopm.config.config import PlopmConfig, SimData
+from plopm.utils.readers import get_xy_coords, get_xz_coords, get_yz_coords
+
+
+
+[docs] +def get_yz_slice( + cfg: PlopmConfig, data: SimData, n: int +) -> tuple[NDArray, NDArray, str, str, int, int, str, str]: + """Prepare geometry and labels for a yz slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map and slice configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple + Coordinate meshes, display and filename slice labels, mapped grid + dimensions, and coordinate-axis names. + + """ + slice_range = cfg.slice[n][0] + nx = data.nx + if slice_range[0] == ":": + cfg.slice[n][0] = [0, nx] + slice_title = f", slice i=0:{nx}" + slice_name = f"0:{nx},j,k" + elif slice_range[0] == slice_range[1] - 1: + start_index = slice_range[0] + 1 + slice_title = f", slice i={start_index}" + slice_name = f"{start_index},j,k" + else: + start_index = slice_range[0] + 1 + end_index = slice_range[1] + slice_title = f", slice i={start_index}:{end_index}" + slice_name = f"{start_index}:{end_index},j,k" + xc, yc = get_yz_coords(cfg, data, n) + mx = 2 * data.ny - 1 + my = 2 * data.nz - 1 + xname = "y" + yname = "z" + return xc, yc, slice_title, slice_name, mx, my, xname, yname
+ + + +
+[docs] +def get_xz_slice( + cfg: PlopmConfig, data: SimData, n: int +) -> tuple[NDArray, NDArray, str, str, int, int, str, str]: + """Prepare geometry and labels for an xz slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map and slice configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple + Coordinate meshes, display and filename slice labels, mapped grid + dimensions, and coordinate-axis names. + + """ + slice_range = cfg.slice[n][1] + ny = data.ny + if slice_range[0] == ":": + cfg.slice[n][1] = [0, ny] + slice_title = f", slice j=0:{ny}" + slice_name = f"i,0:{ny},k" + elif slice_range[0] == slice_range[1] - 1: + start_index = slice_range[0] + 1 + slice_title = f", slice j={start_index}" + slice_name = f"i,{start_index},k" + else: + start_index = slice_range[0] + 1 + end_index = slice_range[1] + slice_title = f", slice j={start_index}:{end_index}" + slice_name = f"i,{start_index}:{end_index},k" + xc, yc = get_xz_coords(cfg, data, n) + mx = 2 * data.nx - 1 + my = 2 * data.nz - 1 + xname = "x" + yname = "z" + return xc, yc, slice_title, slice_name, mx, my, xname, yname
+ + + +
+[docs] +def get_xy_slice( + cfg: PlopmConfig, data: SimData, n: int +) -> tuple[NDArray, NDArray, str, str, int, int, str, str]: + """Prepare geometry and labels for an xy slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map and slice configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple + Coordinate meshes, display and filename slice labels, mapped grid + dimensions, and coordinate-axis names. + + """ + slice_range = cfg.slice[n][2] + nz = data.nz + if slice_range[0] == ":": + cfg.slice[n][2] = [0, nz] + slice_title = f", slice k={1}:{nz}" + slice_name = f"i,j,{1}:{nz}" + elif slice_range[0] == slice_range[1] - 1: + start_index = slice_range[0] + 1 + slice_title = f", slice k={start_index}" + slice_name = f"i,j,{start_index}" + else: + start_index = slice_range[0] + 1 + end_index = slice_range[1] + slice_title = f", slice k={start_index}:{end_index}" + slice_name = f"i,j,{start_index}:{end_index}" + xc, yc = get_xy_coords(cfg, data, n) + mx = 2 * data.nx - 1 + my = 2 * data.ny - 1 + xname = "x" + yname = "y" + return xc, yc, slice_title, slice_name, mx, my, xname, yname
+ + + +
+[docs] +def transform_grid( + cfg: PlopmConfig, n: int, xc: NDArray, yc: NDArray +) -> tuple[NDArray, NDArray]: + """Rotate and translate a two-dimensional coordinate mesh. + + Parameters + ---------- + cfg : PlopmConfig + Rotation and translation settings. + n : int + Map index. + xc, yc : np.ndarray + Coordinate meshes to transform. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Transformed x- and y-coordinate meshes. + + """ + grd = int(cfg.rotation[n]) + angle = grd * np.pi / 180 + cos_val = np.cos(angle) + sin_val = np.sin(angle) + length = xc[-1][-1] - xc[0][0] + width = yc[0][-1] - yc[-1][0] + x_dis = float(cfg.translation[n][0][1:]) + y_dis = float(cfg.translation[n][1][:-1]) + base_x = 1.5 * length + base_y = 1.5 * width + dx = xc - base_x + dy = yc - base_y + return ( + base_x + x_dis + dx * cos_val - dy * sin_val, + base_y + y_dis + dy * cos_val + dx * sin_val, + )
+ + + +
+[docs] +def map_xz( + cfg: PlopmConfig, + data: SimData, + var: str, + values: NDArray, + n: int, + mx: int, + my: int, + features: list | None = None, + feature_id: int = 1, +) -> NDArray: + """Aggregate active-cell values onto an xz slice. + + Values are aggregated through the selected j interval. Permeability uses + arithmetic or harmonic thickness weighting according to flow direction; + other properties use the configured aggregation or pore-volume weighting. + + Parameters + ---------- + cfg : PlopmConfig + Slice and aggregation configuration. + data : SimData + Loaded grid properties and active-cell mapping. + var : str + Variable name. + values : np.ndarray + Values in active-cell order. + n : int + Map index. + mx, my : int + Mapped grid dimensions. + features : list, optional + Wells or faults grouped by label. + feature_id : int, default: 1 + Category assigned when mapping one feature. + + Returns + ------- + np.ndarray + Values on the flattened xz plotting grid. + + """ + how = cfg.aggregation[n] + nx = data.nx + ny = data.ny + nz = data.nz + slice_start, slice_end = cfg.slice[n][1] + layer_size = nx * ny + porv = data.porv + active_idx = data.active_idx + dy = data.dy + mapped_values = np.full(mx * my, np.nan) + is_wells_or_faults = features is not None + is_sum_property = var in cfg.mass_vars or var in [ + "porv", + "dy", + "tranx", + "tranz", + ] + is_caprock = var in cfg.caprock_vars + is_arithmetic_perm = var in ["permx", "permz"] + for k in range(nz): + layer_offset = k * layer_size + output_layer_offset = 2 * (nz - k - 1) * mx + for i in range(nx): + p_v, val, d_y = 0.0, 0.0, 0.0 + if how == "min": + val = np.inf + if how == "max": + val = -np.inf + for sld in range(slice_start, slice_end): + ind = i + sld * nx + layer_offset + cell_pv = porv[ind] + if cell_pv > 0: + active_id = active_idx[ind] + if how and not is_wells_or_faults: + if how == "first": + p_v = 1.0 + if var == "index_i": + val = i + 1 + elif var == "index_j": + val = sld + 1 + elif var == "index_k": + val = k + 1 + else: + val = values[active_id] + break + if how == "last": + p_v = 1.0 + if var == "index_i": + val = i + 1 + elif var == "index_j": + val = sld + 1 + elif var == "index_k": + val = k + 1 + else: + val = values[active_id] + elif how == "min": + p_v = 1.0 + val = min(val, values[active_id]) + elif how == "max": + p_v = 1.0 + val = max(val, values[active_id]) + elif how == "sum": + p_v = 1.0 + val += values[active_id] + elif how == "mean": + p_v += 1.0 + val += values[active_id] + elif how == "pvmean": + p_v += cell_pv + val += values[active_id] * cell_pv + elif how == "harmonic": + cell_value = values[active_id] + d_y += dy[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dy[active_id] / cell_value + ) + p_v += cell_pv + elif how == "arithmetic": + p_v += dy[active_id] + val += values[active_id] * dy[active_id] + elif is_sum_property: + p_v = 1.0 + val += values[active_id] + elif is_caprock: + p_v = 1.0 + val = values[active_id] + break + elif is_arithmetic_perm: + p_v += dy[active_id] + val += values[active_id] * dy[active_id] + elif var == "permy": + cell_value = values[active_id] + p_v = 1 + d_y += dy[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dy[active_id] / cell_value + ) + elif var == "grid": + p_v = 1 + val = 1 + elif var in ["wells", "faults"]: + p_v = 1 + val = feature_id + elif var == "index_i": + p_v = 1 + val = i + 1 + elif var == "index_j": + p_v = 1 + val = sld + 1 + elif var == "index_k": + p_v = 1 + val = k + 1 + else: + p_v += cell_pv + val += values[active_id] * cell_pv + if how == "harmonic" or (not how and var == "permy"): + mapped_values[2 * i + output_layer_offset] = ( + np.nan + if p_v == 0 + else 0.0 if val == np.inf else np.nan if val == 0 else d_y / val + ) + else: + mapped_values[2 * i + output_layer_offset] = ( + np.nan if p_v == 0 else val / p_v + ) + if is_wells_or_faults: + assert features is not None + for index, vals in enumerate(features): + for value in vals: + if value: + for k in range(value[2], value[3] + 1): + ind = value[0] + value[1] * nx + k * layer_size + if not cfg.global_range: + if porv[ind] > 0 and slice_start <= value[1] < slice_end: + mapped_values[2 * value[0] + 2 * (nz - k - 1) * mx] = ( + index + 1 + ) + else: + if porv[ind] > 0: + mapped_values[2 * value[0] + 2 * (nz - k - 1) * mx] = ( + index + 1 + ) + return mapped_values
+ + + +
+[docs] +def map_yz( + cfg: PlopmConfig, + data: SimData, + var: str, + values: NDArray, + n: int, + mx: int, + my: int, + features: list | None = None, + feature_id: int = 1, +) -> NDArray: + """Aggregate active-cell values onto a yz slice. + + Values are aggregated through the selected i interval. Permeability uses + arithmetic or harmonic thickness weighting according to flow direction; + other properties use the configured aggregation or pore-volume weighting. + + Parameters + ---------- + cfg : PlopmConfig + Slice and aggregation configuration. + data : SimData + Loaded grid properties and active-cell mapping. + var : str + Variable name. + values : np.ndarray + Values in active-cell order. + n : int + Map index. + mx, my : int + Mapped grid dimensions. + features : list, optional + Wells or faults grouped by label. + feature_id : int, default: 1 + Category assigned when mapping one feature. + + Returns + ------- + np.ndarray + Values on the flattened yz plotting grid. + + """ + how = cfg.aggregation[n] + nx = data.nx + ny = data.ny + nz = data.nz + slice_start, slice_end = cfg.slice[n][0] + layer_size = nx * ny + porv = data.porv + active_idx = data.active_idx + dx = data.dx + mapped_values = np.full(mx * my, np.nan) + is_wells_or_faults = features is not None + is_sum_property = var in cfg.mass_vars or var in [ + "porv", + "dx", + "trany", + "tranz", + ] + is_caprock = var in cfg.caprock_vars + is_arithmetic_perm = var in ["permy", "permz"] + for k in range(nz): + layer_offset = k * layer_size + output_layer_offset = 2 * (nz - k - 1) * mx + for j in range(ny): + row_offset = j * nx + p_v, val, d_x = 0.0, 0.0, 0.0 + if how == "min": + val = np.inf + if how == "max": + val = -np.inf + for sld in range(slice_start, slice_end): + ind = sld + row_offset + layer_offset + cell_pv = porv[ind] + if cell_pv > 0: + active_id = active_idx[ind] + if how and not is_wells_or_faults: + if how == "first": + p_v = 1.0 + if var == "index_i": + val = sld + 1 + elif var == "index_j": + val = j + 1 + elif var == "index_k": + val = k + 1 + else: + val = values[active_id] + break + if how == "last": + p_v = 1.0 + if var == "index_i": + val = sld + 1 + elif var == "index_j": + val = j + 1 + elif var == "index_k": + val = k + 1 + else: + val = values[active_id] + elif how == "min": + p_v = 1.0 + val = min(val, values[active_id]) + elif how == "max": + p_v = 1.0 + val = max(val, values[active_id]) + elif how == "sum": + p_v = 1.0 + val += values[active_id] + elif how == "mean": + p_v += 1.0 + val += values[active_id] + elif how == "pvmean": + p_v += cell_pv + val += values[active_id] * cell_pv + elif how == "harmonic": + cell_value = values[active_id] + d_x += dx[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dx[active_id] / cell_value + ) + p_v += cell_pv + elif how == "arithmetic": + p_v += dx[active_id] + val += values[active_id] * dx[active_id] + elif is_sum_property: + p_v = 1.0 + val += values[active_id] + elif is_caprock: + p_v = 1.0 + val = values[active_id] + break + elif is_arithmetic_perm: + p_v += dx[active_id] + val += values[active_id] * dx[active_id] + elif var == "permx": + cell_value = values[active_id] + p_v = 1 + d_x += dx[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dx[active_id] / cell_value + ) + elif var == "grid": + p_v = 1 + val = 1 + elif var in ["wells", "faults"]: + p_v = 1 + val = feature_id + elif var == "index_i": + p_v = 1 + val = sld + 1 + elif var == "index_j": + p_v = 1 + val = j + 1 + elif var == "index_k": + p_v = 1 + val = k + 1 + else: + p_v += cell_pv + val += values[active_id] * cell_pv + if how == "harmonic" or (not how and var == "permx"): + mapped_values[2 * j + output_layer_offset] = ( + np.nan + if p_v == 0 + else 0.0 if val == np.inf else np.nan if val == 0 else d_x / val + ) + else: + mapped_values[2 * j + output_layer_offset] = ( + np.nan if p_v == 0 else val / p_v + ) + if is_wells_or_faults: + assert features is not None + for index, vals in enumerate(features): + for value in vals: + if value: + for k in range(value[2], value[3] + 1): + ind = value[0] + value[1] * nx + k * layer_size + if not cfg.global_range: + if porv[ind] > 0 and slice_start <= value[0] < slice_end: + mapped_values[2 * value[1] + 2 * (nz - k - 1) * mx] = ( + index + 1 + ) + else: + if porv[ind] > 0: + mapped_values[2 * value[1] + 2 * (nz - k - 1) * mx] = ( + index + 1 + ) + return mapped_values
+ + + +
+[docs] +def map_xy( + cfg: PlopmConfig, + data: SimData, + var: str, + values: NDArray, + n: int, + mx: int, + my: int, + features: list | None = None, + feature_id: int = 1, +) -> NDArray: + """Aggregate active-cell values onto an xy slice. + + Values are aggregated through the selected k interval. Dual-porosity rows + are included when enabled, and permeability is weighted according to the + vertical flow direction. + + Parameters + ---------- + cfg : PlopmConfig + Slice, aggregation, and dual-grid configuration. + data : SimData + Loaded grid properties and active-cell mapping. + var : str + Variable name. + values : np.ndarray + Values in active-cell order. + n : int + Map index. + mx, my : int + Mapped grid dimensions. + features : list, optional + Wells or faults grouped by label. + feature_id : int, default: 1 + Category assigned when mapping one feature. + + Returns + ------- + np.ndarray + Values on the flattened xy plotting grid. + + """ + how = cfg.aggregation[n] + nx = data.nx + ny_total = data.ny + dual = cfg.dual_grid[n] == "1" if n < len(cfg.dual_grid) else False + ny = int((ny_total - 1) / 2) if dual else ny_total + slice_start, slice_end = cfg.slice[n][2] + layer_size = nx * ny_total + porv = data.porv + active_idx = data.active_idx + dz = data.dz + mapped_values = np.full(mx * my, np.nan) + is_wells_or_faults = features is not None + is_sum_property = var in cfg.mass_vars or var in [ + "porv", + "dz", + "tranx", + "trany", + ] + is_caprock = var in cfg.caprock_vars + is_arithmetic_perm = var in ["permx", "permy"] + for j in range(ny): + row_offset = j * nx + dual_row_offset = (j + ny + 1) * nx + for i in range(nx): + p_v, val, d_z = 0.0, 0.0, 0.0 + if how == "min": + val = np.inf + if how == "max": + val = -np.inf + for sld in range(slice_start, slice_end): + layer_offset = sld * layer_size + ind = i + row_offset + layer_offset + idd = i + dual_row_offset + layer_offset + cell_pv = porv[ind] + dual_cell_pv = porv[idd] if dual else 0 + if cell_pv > 0 or (dual and dual_cell_pv > 0): + active_id = active_idx[ind] + dual_active_id = active_idx[idd] if dual else active_id + if how and not is_wells_or_faults: + if how == "first": + p_v = 1.0 + if var == "index_i": + val = i + 1 + elif var == "index_j": + val = j + 1 + elif var == "index_k": + val = sld + 1 + else: + val = values[active_id] + break + if how == "last": + p_v = 1.0 + if var == "index_i": + val = i + 1 + elif var == "index_j": + val = j + 1 + elif var == "index_k": + val = sld + 1 + else: + val = values[active_id] + elif how == "min": + p_v = 1.0 + if cell_pv > 0: + val = min(val, values[active_id]) + if dual and dual_cell_pv > 0: + val = min(val, values[dual_active_id]) + elif how == "max": + p_v = 1.0 + if cell_pv > 0: + val = max(val, values[active_id]) + if dual and dual_cell_pv > 0: + val = max(val, values[dual_active_id]) + elif how == "sum": + p_v = 1.0 + if cell_pv > 0: + val += values[active_id] + if dual and dual_cell_pv > 0: + val += values[dual_active_id] + elif how == "mean": + if cell_pv > 0: + p_v += 1.0 + val += values[active_id] + if dual and dual_cell_pv > 0: + p_v += 1.0 + val += values[dual_active_id] + elif how == "pvmean": + if cell_pv > 0: + p_v += cell_pv + val += values[active_id] * cell_pv + if dual and dual_cell_pv > 0: + p_v += dual_cell_pv + val += values[dual_active_id] * dual_cell_pv + elif how == "harmonic": + if cell_pv > 0: + cell_value = values[active_id] + d_z += dz[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dz[active_id] / cell_value + ) + p_v += cell_pv + if dual and dual_cell_pv > 0: + cell_value = values[dual_active_id] + d_z += dz[dual_active_id] + val = ( + np.inf + if cell_value == 0 + else val + dz[dual_active_id] / cell_value + ) + p_v += dual_cell_pv + elif how == "arithmetic": + if cell_pv > 0: + p_v += dz[active_id] + val += values[active_id] * dz[active_id] + if dual and dual_cell_pv > 0: + p_v += dz[dual_active_id] + val += values[dual_active_id] * dz[dual_active_id] + elif is_sum_property: + p_v = 1.0 + if cell_pv > 0: + val += values[active_id] + if dual and dual_cell_pv > 0: + val += values[dual_active_id] + elif is_caprock: + p_v = 1.0 + val = values[active_id] + break + elif is_arithmetic_perm: + if cell_pv > 0: + p_v += dz[active_id] + val += values[active_id] * dz[active_id] + if dual and dual_cell_pv > 0: + p_v += dz[dual_active_id] + val += values[dual_active_id] * dz[dual_active_id] + elif var == "permz": + p_v = 1 + if cell_pv > 0: + cell_value = values[active_id] + d_z += dz[active_id] + val = ( + np.inf + if cell_value == 0 + else val + dz[active_id] / cell_value + ) + if dual and dual_cell_pv > 0: + cell_value = values[dual_active_id] + d_z += dz[dual_active_id] + val = ( + np.inf + if cell_value == 0 + else val + dz[dual_active_id] / cell_value + ) + elif var == "grid": + p_v = 1 + val = 1 + elif var in ["wells", "faults"]: + p_v = 1 + val = feature_id + elif var == "index_i": + p_v = 1 + val = i + 1 + elif var == "index_j": + p_v = 1 + val = j + 1 + elif var == "index_k": + p_v = 1 + val = sld + 1 + else: + if cell_pv > 0: + p_v += cell_pv + val += values[active_id] * cell_pv + if dual and dual_cell_pv > 0: + p_v += dual_cell_pv + val += values[dual_active_id] * dual_cell_pv + if how == "harmonic" or (not how and var == "permz"): + mapped_values[2 * i + 2 * j * mx] = ( + np.nan + if p_v == 0 + else 0.0 if val == np.inf else np.nan if val == 0 else d_z / val + ) + else: + mapped_values[2 * i + 2 * j * mx] = np.nan if p_v == 0 else val / p_v + if is_wells_or_faults: + assert features is not None + for index, vals in enumerate(features): + for value in vals: + if value: + for k in range(value[2], value[3] + 1): + ind = value[0] + value[1] * nx + k * layer_size + if not cfg.global_range: + if porv[ind] > 0 and slice_start <= k < slice_end: + mapped_values[2 * value[0] + 2 * value[1] * mx] = ( + index + 1 + ) + else: + if porv[ind] > 0: + mapped_values[2 * value[0] + 2 * value[1] * mx] = ( + index + 1 + ) + if dual and cfg.difference_input: + mapped_values = mapped_values[: (2 * nx - 1) * (2 * ny - 1)] + return mapped_values
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/readers.html b/docs/_modules/plopm/utils/readers.html new file mode 100644 index 0000000..2f124bd --- /dev/null +++ b/docs/_modules/plopm/utils/readers.html @@ -0,0 +1,2413 @@ + + + + + + + + + + plopm.utils.readers — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.readers

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=R0911,R0912,R0913,R0915,R0917,R1702,R0914,C0302,E1102
+
+"""Read and derive plotting quantities from OPM Flow output.
+
+The module opens INIT, UNRST, EGRID, SMSPEC, deck, and CSV data; constructs
+plotting coordinates; evaluates variable expressions; and derives saturation,
+mass, caprock, distance, well, and fault quantities.
+"""
+
+import csv
+import datetime
+import os
+import sys
+from contextlib import nullcontext
+
+import numpy as np
+from alive_progress import alive_bar
+from numpy.typing import NDArray
+from opm.io.ecl import EclFile as OpmFile
+from opm.io.ecl import EGrid as OpmGrid
+from opm.io.ecl import ERst as OpmRestart
+from opm.io.ecl import ESmry as OpmSummary
+
+from plopm.config.config import PlopmConfig, SimData
+from plopm.utils.initialization import mass_unit, spatial_unit
+from plopm.utils.terminal import (
+    cli_error_value,
+    cli_info_value,
+    plopm_error,
+    plopm_info,
+)
+
+csv.field_size_limit(sys.maxsize)
+
+GAS_DEN_REF = 1.86843
+WAT_DEN_REF = 998.108
+
+
+
+[docs] +def read_case( + deck: str, + gif: bool, + vtk: bool, + variables: list, + restart: list, + filters: list, + n: int = 0, +) -> SimData: + """Open the OPM output required for one simulation case. + + Parameters + ---------- + deck : str + Simulation-case stem without an extension. + gif, vtk : bool + Output modes controlling restart and grid loading. + variables : list + Requested variables or expressions. + restart : list + Requested restart report steps. + filters : list + Property-filter expressions. + n : int, default: 0 + Case index used to select per-case settings. + + Returns + ------- + SimData + Loaded readers, grid properties, and report-step metadata. + + """ + if os.path.isfile(f"{deck}.INIT"): + init = OpmFile(f"{deck}.INIT") + else: + plopm_error(f"unable to find {cli_error_value(f'{deck}.INIT')}") + unrst = OpmRestart(f"{deck}.UNRST") if os.path.isfile(f"{deck}.UNRST") else None + egrid = ( + OpmGrid(f"{deck}.EGRID") + if os.path.isfile(f"{deck}.EGRID") and not vtk + else None + ) + + porv = np.array(init["PORV"]) + dx = np.array(init["DX"]) + dy = np.array(init["DY"]) + dz = np.array(init["DZ"]) + + act_mask = porv > 0 + pv = porv[act_mask] + actind = np.cumsum(act_mask) - 1 + + tnrst = [] + ntot = 1 + + if filters[n]: + porv0 = porv.copy() + for value in filters[n].split("&"): + filte = value.strip().split(" ") + key = filte[0].upper() + if init.count(key): + arr = np.array(init[key]) + mask = porv0 > 0 + porv[mask] = _apply_filter(porv[mask], arr, filte[1], float(filte[2])) + + if unrst: + steps = unrst.report_steps + ntot = steps[-1] + 1 + if unrst.count("DOUBHEAD", 0): + tnrst = [unrst["DOUBHEAD", ntm][0] for ntm in steps] + if restart[0] == -1: + restart = unrst.report_steps if gif else [ntot - 1] + elif restart[0] == -1: + restart = [ntot - 1] + + nx = ny = nz = 0 + + if egrid: + dim = egrid.dimension + nx, ny, nz = dim + elif "index_i" in variables or "index_j" in variables or "index_k" in variables: + grid = OpmGrid(f"{deck}.EGRID") + dim = grid.dimension + nx, ny, nz = dim + + if not tnrst: + tnrst = [0] * len(restart) + + return SimData( + init, + unrst, + egrid, + porv, + dx, + dy, + dz, + pv, + actind, + restart, + tnrst, + porv.size, + ntot, + nx, + ny, + nz, + )
+ + + +
+[docs] +def get_yz_coords(cfg: PlopmConfig, data: SimData, n: int) -> tuple[NDArray, NDArray]: + """Build coordinate meshes for a yz slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Y- and z-coordinate meshes. + + """ + xyz_func = data.grid.xyz_from_ijk + ny_val = data.ny + nz_val = data.nz + base_i_all = cfg.slice[n][0][0] + total_size = nz_val * 4 * ny_val + xc_list = [0] * total_size + yc_list = [0] * total_size + idx = 0 + for j in range(nz_val): + base_k = nz_val - j - 1 + base_idx_second = idx + 2 * ny_val + tmp_idx = base_idx_second + for i in range(ny_val): + val = xyz_func(base_i_all, i, base_k, True) + xc_list[idx] = val[1][4] + yc_list[idx] = val[2][4] + idx += 1 + xc_list[idx] = val[1][6] + yc_list[idx] = val[2][6] + idx += 1 + xc_list[tmp_idx] = val[1][0] + yc_list[tmp_idx] = val[2][0] + tmp_idx += 1 + xc_list[tmp_idx] = val[1][2] + yc_list[tmp_idx] = val[2][2] + tmp_idx += 1 + idx = base_idx_second + 2 * ny_val + xc_array = np.asarray(xc_list) + yc_array = np.asarray(yc_list) + return xc_array.reshape(2 * nz_val, 2 * ny_val), yc_array.reshape( + 2 * nz_val, 2 * ny_val + )
+ + + +
+[docs] +def get_xz_coords(cfg: PlopmConfig, data: SimData, n: int) -> tuple[NDArray, NDArray]: + """Build coordinate meshes for an xz slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + X- and z-coordinate meshes. + + """ + xyz_func = data.grid.xyz_from_ijk + nx_val = data.nx + nz_val = data.nz + base_j_all = cfg.slice[n][1][0] + total_size = nz_val * 4 * nx_val + xc_list = [0] * total_size + yc_list = [0] * total_size + idx = 0 + for j in range(nz_val): + base_k = nz_val - j - 1 + base_idx_second = idx + 2 * nx_val + tmp_idx = base_idx_second + for i in range(nx_val): + val = xyz_func(i, base_j_all, base_k, True) + xc_list[idx] = val[0][4] + yc_list[idx] = val[2][4] + idx += 1 + xc_list[idx] = val[0][5] + yc_list[idx] = val[2][5] + idx += 1 + xc_list[tmp_idx] = val[0][0] + yc_list[tmp_idx] = val[2][0] + tmp_idx += 1 + xc_list[tmp_idx] = val[0][1] + yc_list[tmp_idx] = val[2][1] + tmp_idx += 1 + idx = base_idx_second + 2 * nx_val + xc_array = np.asarray(xc_list) + yc_array = np.asarray(yc_list) + return xc_array.reshape(2 * nz_val, 2 * nx_val), yc_array.reshape( + 2 * nz_val, 2 * nx_val + )
+ + + +
+[docs] +def get_xy_coords(cfg: PlopmConfig, data: SimData, n: int) -> tuple[NDArray, NDArray]: + """Build coordinate meshes for an xy slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + data : SimData + Loaded grid data. + n : int + Slice index. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + X- and y-coordinate meshes. + + """ + xyz_func = data.grid.xyz_from_ijk + nx_val = data.nx + ny_val = data.ny + base_k_all = cfg.slice[n][2][0] + total_size = ny_val * 4 * nx_val + xc_list = [0] * total_size + yc_list = [0] * total_size + idx = 0 + for j in range(ny_val): + base_idx_second = idx + 2 * nx_val + tmp_idx = base_idx_second + for i in range(nx_val): + val = xyz_func(i, j, base_k_all, True) + xc_list[idx] = val[0][0] + yc_list[idx] = val[1][0] + idx += 1 + xc_list[idx] = val[0][1] + yc_list[idx] = val[1][1] + idx += 1 + xc_list[tmp_idx] = val[0][2] + yc_list[tmp_idx] = val[1][2] + tmp_idx += 1 + xc_list[tmp_idx] = val[0][3] + yc_list[tmp_idx] = val[1][3] + tmp_idx += 1 + idx = base_idx_second + 2 * nx_val + xc_array = np.asarray(xc_list) + yc_array = np.asarray(yc_list) + return xc_array.reshape(2 * ny_val, 2 * nx_val), yc_array.reshape( + 2 * ny_val, 2 * nx_val + )
+ + + +def _resolve_var( + cfg: PlopmConfig, + data: SimData, + key_up: str, + key_low: str, + step: int, + init: OpmFile, + unrst: OpmRestart, + mass_all: list, + caprock_list: list, +): + """Resolve a variable from stored or derived quantities. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration. + data : SimData + Loaded simulation data. + key_up, key_low : str + OPM keyword and normalized variable name. + step : int + Restart report step. + init : OpmFile + INIT reader. + unrst : OpmRestart + UNRST reader. + mass_all, caprock_list : list + Supported derived variable names. + + Returns + ------- + np.ndarray or None + Resolved values, or ``None`` when unavailable. + + """ + if init.count(key_up): + return 1.0 * init[key_up, 0] + if unrst is not None and unrst.count(key_up, step): + return 1.0 * unrst[key_up, step] + if key_low in mass_all: + return _get_mass(data, key_low, step) + if key_low in caprock_list: + val, _ = _get_caprock(data, key_low, step, cfg.stress_coefficient) + return val + if key_low in ["swat", "soil", "sgas"]: + return _get_saturation(data.unrst, key_low, step) + return None + + +def _read_histogram( + cfg: PlopmConfig, data: SimData, tokens: list, step: int +) -> NDArray: + """Read values used to create a histogram. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration. + data : SimData + Loaded simulation data. + tokens : list + Parsed variable-expression tokens. + step : int + Restart report step. + + Returns + ------- + np.ndarray + Values in global cell order with inactive cells set to NaN. + + """ + quan0_low = tokens[0] + quan0 = quan0_low.upper() + porv = data.porv + nxyz = data.ncells + init = data.init + unrst = data.unrst + mass_all = cfg.mass_vars + cfg.mass_fracs + caprock_list = cfg.caprock_vars + if quan0 != "PORV": + act = porv > 0 + else: + act = porv > -1 + var = np.nan * np.ones(nxyz, dtype=float) + result = _resolve_var( + cfg, data, quan0, quan0_low, step, init, unrst, mass_all, caprock_list + ) + if result is not None: + var[act] = result + else: + plopm_error(f"not found {cli_error_value(f'-v {tokens[0]}')}.") + if len(tokens) > 1: + ops = tokens[1::2] + for j, val in enumerate(tokens[2::2]): + val_up = val.upper() + if val[0].isdigit() and not val[-1].isdigit(): + if unrst is None: + plopm_error(f"not found {cli_error_value(f'-v {val}')}.") + other = 1.0 * unrst[val[1:].upper(), int(val[0])] + elif val[0].isdigit() and val[-1].isdigit(): + other = np.full_like(var[act], float(val)) + else: + other = _resolve_var( + cfg, + data, + val_up, + val, + step, + init, + unrst, + mass_all, + caprock_list, + ) + if other is None: + plopm_error(f"not found {cli_error_value(f'-v {val}')}.") + var_act = var[act] + var[act] = _apply_operator(var_act, other, ops[j]) + return var + + +def _compute_distance( + cfg: PlopmConfig, data: SimData, tokens: list, n: int +) -> tuple[NDArray, NDArray]: + """Compute distance from selected cells to target points. + + Parameters + ---------- + cfg : PlopmConfig + Distance and sensor configuration. + data : SimData + Loaded simulation data. + tokens : list + Parsed expression selecting active cells. + n : int + Plot index. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Finite distances and their simulation times. + + """ + xyz_func = data.grid.xyz_from_ijk + nx_val = data.nx + ny_val = data.ny + nz_val = data.nz + nxyz = data.ncells + ntot = data.nsteps + porv = data.porv + init = data.init + unrst = data.unrst + mass_all = cfg.mass_vars + cfg.mass_fracs + distance_type = cfg.distance[0] + xyz = np.zeros((nxyz, 3), dtype=float) + act = porv > 0 + time = np.array(data.times) + distance = np.nan * np.ones(ntot) + index = 0 + for k in range(nz_val): + for j in range(ny_val): + for i in range(nx_val): + xyz[index, :] = np.mean(xyz_func(i, j, k, True), axis=1) + index += 1 + if cfg.distance[1] == "sensor": + ind = ( + cfg.slice[n][0] + + cfg.slice[n][1] * nx_val + + cfg.slice[n][2] * nx_val * ny_val + ) + points = [xyz[ind, :]] + sensor_loc = f"[{points[0][0]:.2E},{points[0][1]:.2E},{points[0][2]:.2E}]" + plopm_info( + f"computing the {cli_info_value(cfg.distance[0])} distance of " + f"{cli_info_value(tokens[0])} to the sensor " + f"{cli_info_value(sensor_loc)} [m]" + ) + else: + points = [] + for k in range(nz_val): + if ny_val > 1: + base_k = k * nx_val * ny_val + for i in range(nx_val): + ind = i + base_k + if act[ind]: + points.append(xyz[ind]) + ind = i + (ny_val - 1) * nx_val + base_k + if act[ind]: + points.append(xyz[ind]) + if nx_val > 1: + base_k = k * nx_val * ny_val + for j in range(ny_val): + ind = j * nx_val + base_k + if act[ind]: + points.append(xyz[ind]) + ind = nx_val - 1 + j * nx_val + base_k + if act[ind]: + points.append(xyz[ind]) + plopm_info( + f"computing the {cli_info_value(cfg.distance[0])} distance of " + f"{cli_info_value(tokens[0])} to the model boundaries" + ) + show_progress = sys.stdout.isatty() + if show_progress: + bar_ctx = alive_bar(ntot * len(points), bar="fish") + else: + bar_ctx = nullcontext() + with bar_ctx as bar_animation: + for step in unrst.report_steps: + xyzt = np.copy(xyz) + var = np.nan * np.ones(nxyz, dtype=float) + quan0_low = tokens[0] + quan0_up = tokens[0].upper() + if quan0_low in ["index_i", "index_j", "index_k"]: + var[act] = _grid_indices(quan0_low, nx_val, ny_val, nz_val) + elif unrst.count(quan0_up, step): + var[act] = 1.0 * unrst[quan0_up, step] + elif quan0_low in mass_all: + var[act] = _get_mass(data, quan0_low, step) + elif quan0_low in ["swat", "soil", "sgas"]: + var[act] = _get_saturation(data.unrst, quan0_low, step) + else: + flag = f"-dist {','.join(cfg.distance)}" + plopm_error( + f"invalid {cli_error_value(f'-v {tokens[0]}')} for " + f"{cli_info_value(flag)}." + ) + if len(tokens) > 1: + ops = tokens[1::2] + for j, val in enumerate(tokens[2::2]): + val_up = val.upper() + if val[0].isdigit() and not val[-1].isdigit(): + other = 1.0 * unrst[val[1:].upper(), int(val[0])] + elif val[0].isdigit() and val[-1].isdigit(): + other = np.full_like(var[act], float(val)) + elif init.count(val_up): + other = 1.0 * init[val_up, 0] + if val_up == "PORV": + other = other[act] + elif val in ["index_i", "index_j", "index_k"]: + var[act] = _grid_indices(val, nx_val, ny_val, nz_val) + continue + elif unrst.count(val_up, step): + other = 1.0 * unrst[val_up, step] + elif val in mass_all: + other = _get_mass(data, val, step) + elif val in ["swat", "soil", "sgas"]: + other = _get_saturation(data.unrst, val, step) + else: + plopm_error(f"not found {cli_error_value(f'-v {val}')}.") + var_act = var[act] + var[act] = _apply_operator(var_act, other, ops[j]) + else: + var[var > 0] = 1 + xyzt[var != 1] = np.nan + temp = np.nan * np.ones(len(points)) + for point_index, point in enumerate(points): + if show_progress: + bar_animation() + vals = np.linalg.norm(xyzt - point, axis=1) + if not np.all(np.isnan(vals)): + if distance_type == "min": + temp[point_index] = np.nanmin(vals) + else: + temp[point_index] = np.nanmax(vals) + if not np.isnan(temp).all(): + if distance_type == "min": + distance[step] = np.nanmin(temp) + else: + distance[step] = np.nanmax(temp) + return distance[~np.isnan(distance)], time[~np.isnan(distance)] + + +def _grid_indices(name: str, nx: int, ny: int, nz: int) -> list: + """Create one-based grid indices in global cell order. + + Parameters + ---------- + name : {"index_i", "index_j", "index_k"} + Grid axis to index. + nx, ny, nz : int + Grid dimensions. + + Returns + ------- + list[int] + One-based indices for all grid cells. + + """ + nxyz = nx * ny * nz + if name == "index_i": + return [(grid_index % nx) + 1 for grid_index in range(nxyz)] + if name == "index_j": + return [((grid_index // nx) % ny) + 1 for grid_index in range(nxyz)] + return [(grid_index // (nx * ny)) + 1 for grid_index in range(nxyz)] + + +def _aggregate(var: NDArray, op: str, porv: NDArray) -> NDArray: + """_aggregate values with the selected method. + + Parameters + ---------- + var : np.ndarray + Values to _aggregate. + op : str + Aggregation method. + porv : np.ndarray + Pore-volume weights used by ``"pvmean"``. + + Returns + ------- + np.ndarray or float + _aggregated values. + + """ + if op == "min": + return np.min(var) + if op == "max": + return np.max(var) + if op == "sum": + return np.sum(var) + if op == "mean": + return np.mean(var) + if op == "pvmean": + return np.sum(var * porv) / np.sum(porv) + plopm_error(f"unknow/unsupported aggregation {cli_error_value(f'-agg {op}')}.") + + +def _read_values( + cfg: PlopmConfig, data: SimData, tokens: list, n: int, ntot: list +) -> tuple[NDArray, NDArray]: + """Read an _aggregated time series or grid-axis profile. + + Parameters + ---------- + cfg : PlopmConfig + Initialized series configuration. + data : SimData + Loaded simulation data. + tokens : list + Parsed variable-expression tokens. + n : int + Plot index. + ntot : list + Restart report steps to evaluate. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Values and corresponding time or grid coordinates. + + """ + slc_val = cfg.slice[n] + axis_index = slc_val.index(-1) if -1 in slc_val else -1 + nx_val = data.nx + ny_val = data.ny + nz_val = data.nz + if axis_index == 0: + xsize = nx_val + elif axis_index == 1: + xsize = ny_val + elif axis_index == 2: + xsize = nz_val + else: + xsize = 1 + if len(ntot) > 1: + tsize = len(ntot) + time = np.array(data.times) + var = 0.0 * np.ones(tsize) + else: + time = np.array(range(xsize), dtype=float) + var = 0.0 * np.ones(xsize) + init = data.init + unrst = data.unrst + mass_all = cfg.mass_vars + cfg.mass_fracs + caprock_list = cfg.caprock_vars + pv_all = data.active_pv + layer_flag = cfg.layer + egrid = data.grid + quan0_low = tokens[0] + quan0_up = quan0_low.upper() + ops = tokens[1::2] if len(tokens) > 1 else [] + for output_index, step in enumerate(ntot): + temp = np.ones(xsize, dtype=float) + porv = np.ones(xsize, dtype=float) + inds = [0] * xsize + if layer_flag: + if axis_index == 0: + for index in range(xsize): + inds[index] = egrid.active_index(index, slc_val[1], slc_val[2]) + elif axis_index == 1: + for index in range(xsize): + inds[index] = egrid.active_index(slc_val[0], index, slc_val[2]) + elif axis_index == 2: + for index in range(xsize): + inds[index] = egrid.active_index(slc_val[0], slc_val[1], index) + else: + ind0 = egrid.active_index(slc_val[0], slc_val[1], slc_val[2]) + for index in range(xsize): + inds[index] = ind0 + if quan0_low in mass_all: + arr_main = _get_mass(data, quan0_low, step) + elif quan0_low in caprock_list: + arr_main, _ = _get_caprock(data, quan0_low, step, cfg.stress_coefficient) + elif quan0_low in ["swat", "soil", "sgas"]: + arr_main = _get_saturation(data.unrst, quan0_low, step) + else: + arr_main = None + if len(tokens) > 1: + arr_vals = [] + for val in tokens[2::2]: + if val in mass_all: + arr_vals.append(_get_mass(data, val, step)) + elif val in caprock_list: + arr, _ = _get_caprock(data, val, step, cfg.stress_coefficient) + arr_vals.append(arr) + elif val in ["swat", "soil", "sgas"]: + arr_vals.append(_get_saturation(data.unrst, val, step)) + else: + arr_vals.append(np.full_like(temp, np.nan)) + inds_arr = np.array(inds) + + if unrst.count("RPORV", step): + porv = unrst["RPORV", step][inds_arr] + else: + porv = pv_all[inds_arr] + + if unrst.count(quan0_up, step): + temp = 1.0 * unrst[quan0_up, step][inds_arr] + # porv-weighted pressure for the dual model + if cfg.dual_grid[n] == "1" and cfg.sensor: + indd = egrid.active_index( + slc_val[0], slc_val[1] + int((data.ny - 1) / 2) + 1, slc_val[2] + ) + presd = unrst[quan0_up, step][indd] + if unrst.count("RPORV", step): + porvd = unrst["RPORV", step][indd] + else: + porvd = pv_all[indd] + temp = (temp * porv + presd * porvd) / (porv + porvd) + elif init.count(quan0_up): + temp = 1.0 * init[quan0_up, 0][inds_arr] + elif arr_main is not None: + temp = arr_main[inds_arr] + else: + plopm_error(f"not found {cli_error_value(f'-v {tokens[0]}')}.") + + if len(tokens) > 1: + for j, val in enumerate(tokens[2::2]): + val_up = val.upper() + arr_val = arr_vals[j] + if val[0].isdigit() and not val[-1].isdigit(): + other = 1.0 * unrst[val[1:].upper(), int(val[0])][inds_arr] + elif val[0].isdigit() and val[-1].isdigit(): + other = np.full_like(temp, float(val)) + elif init.count(val_up): + other = 1.0 * init[val_up, 0][inds_arr] + elif unrst.count(val_up, step): + other = 1.0 * unrst[val_up, step][inds_arr] + elif not np.isnan(arr_val).all(): + other = arr_val[inds_arr] + else: + plopm_error(f"not found {cli_error_value(f'-v {val}')}.") + temp = _apply_operator(temp, other, ops[j]) + ll = np.arange(xsize) + output_index + if cfg.aggregation[0]: + var[output_index] = _aggregate(temp, cfg.aggregation[0], porv) + elif layer_flag: + var = temp + else: + if xsize == 1: + var[ll] = temp[0] + else: + var[ll] = temp + if layer_flag and not cfg.aggregation[0]: + xyz_func = egrid.xyz_from_ijk + if axis_index == 0: + for i in range(nx_val): + time[i] = np.mean(xyz_func(i, slc_val[1], slc_val[2], True), axis=1)[0] + elif axis_index == 1: + for j in range(ny_val): + time[j] = np.mean(xyz_func(slc_val[0], j, slc_val[2], True), axis=1)[1] + else: + for k in range(nz_val): + time[k] = np.mean(xyz_func(slc_val[0], slc_val[1], k, True), axis=1)[2] + return var, time + + +
+[docs] +def read_series( + cfg: PlopmConfig, case: str, values: str, tunit: str, qskl: float, n: int +) -> tuple[NDArray, NDArray, str, str]: + """Read one one-dimensional series for plotting. + + Parameters + ---------- + cfg : PlopmConfig + Initialized series configuration. + case : str + Simulation-case stem or CSV path. + values : str + Variable name or expression. + tunit : str + Requested time-unit code. + qskl : float + Scale factor applied to values. + n : int + Plot or case index. + + Returns + ------- + tuple[np.ndarray, np.ndarray, str, str] + Coordinates, values, coordinate unit, and value unit. + + """ + time, vunit = np.array([0, 1]), "" + tskl, tunit = time_unit(tunit) + tokens = values.split(" ") + csv_flag = cfg.csv_columns[n][0] + q0_low = tokens[0] + use_sw = "krw" in "".join(cfg.variables) + if csv_flag: + csvv = np.genfromtxt(f"{case}.csv", delimiter=",", skip_header=1) + col_t = cfg.csv_columns[n][0] - 1 + col_v = cfg.csv_columns[n][1] - 1 + time = tskl * csvv[:, col_t] / 86400.0 + var = csvv[:, col_v] + elif cfg.distance[0]: + xskl, xunit = spatial_unit(cfg.xunits) + data = read_case( + case, cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters + ) + var, time = _compute_distance(cfg, data, tokens, n) + vunit = f" ({cfg.distance[0]} distance to {cfg.distance[1]} in {xunit})" + var *= xskl + elif cfg.histogram[0]: + data = read_case( + case, cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters + ) + var = _read_histogram(cfg, data, tokens, data.steps[0]) + tunit = "" + elif cfg.sensor or cfg.aggregation[0]: + data = read_case( + case, cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters + ) + var, time = _read_values(cfg, data, tokens, n, data.unrst.report_steps) + time *= tskl + if tunit == "Dates": + dates = [] + unrst = data.unrst + + for step in range(len(unrst)): + intehead = unrst["INTEHEAD", step] + dates.append( + datetime.date( + year=int(intehead[66]), + month=int(intehead[65]), + day=int(intehead[64]), + ) + ) + + time = np.asarray(dates) + elif cfg.layer: + xskl, tunit = spatial_unit(cfg.xunits) + data = read_case( + case, cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters + ) + tmp = data.steps[n] if n < len(cfg.restart) else data.steps[0] + var, time = _read_values(cfg, data, tokens, n, [tmp]) + time *= xskl + elif q0_low[:3] in ["krw", "krg"] or q0_low[:4] in [ + "krog", + "krow", + "pcow", + "pcog", + "pcwg", + ]: + snu = 1 + hyst = False + if q0_low[-1] == "h": + hyst = True + q0_low = tokens[0][:-1] + if len(q0_low) == 3: + what = q0_low[:3] + elif q0_low in ["krow", "krog", "pcow", "pcog", "pcwg"]: + what = q0_low[:4] + elif q0_low[:3] in ["krw", "krg"]: + what = q0_low[:3] + snu = int(tokens[0][3:]) + else: + what = q0_low[:4] + snu = int(tokens[0][4:]) + if not os.path.isfile(f"{case}.INIT"): + plopm_error( + f"Missing {cli_error_value(f'{case}.INIT')}, required by " + f"{cli_info_value(f'-v {q0_low}')}." + ) + init = OpmFile(f"{case}.INIT") + tabdim = init["TABDIMS"] + table = np.array(init["TAB"]) + nswe = tabdim[24] + nsnum = tabdim[25] + vunit = "" + if what == "krg": + tunit = "s$_w$ [-]" if use_sw else "s$_g$ [-]" + sht = tabdim[23] - 1 + base = sht + (snu - 1) * nswe + time = table[base : base + nswe] + time = time[time <= 1.0] + count_v = len(time) + var = table[ + sht + nswe * nsnum + (snu - 1) * nswe : sht + nswe * nsnum + snu * nswe + ][:count_v] + if hyst: + base2 = sht + (nsnum // 2 + snu - 1) * nswe + timeh = table[base2 : base2 + nswe] + timeh = timeh[timeh <= 1.0] + count_v = len(timeh) + var = np.append( + var, + np.flip( + table[ + sht + + nswe * nsnum + + (nsnum // 2 + snu - 1) * nswe : sht + + nswe * nsnum + + (nsnum // 2 + snu) * nswe + ][:count_v] + ), + ) + time = np.append(time, np.flip(timeh)) + if use_sw: + time = 1.0 - time + elif what == "krow": + nswe = tabdim[21] + tunit = "s$_w$ [-]" + sht = tabdim[26] - 1 + base = sht + (snu - 1) * nswe + time = table[base : base + nswe] + time = time[time <= 1.0] + count_v = len(time) + if tabdim[22] == 2: + sht += nswe + var = np.flip( + table[ + sht + + nswe * nsnum + + (snu - 1) * nswe : sht + + nswe * nsnum + + snu * nswe + ][:count_v] + ) + elif what == "krw": + nswe = tabdim[21] + tunit = "s$_w$ [-]" + sht = tabdim[20] - 1 + base = sht + (snu - 1) * nswe + time = table[base : base + nswe] + time = time[time <= 1.0] + count_v = len(time) + var = table[ + sht + nswe * nsnum + (snu - 1) * nswe : sht + nswe * nsnum + snu * nswe + ][:count_v] + if hyst: + base2 = sht + (nsnum // 2 + snu - 1) * nswe + timeh = table[base2 : base2 + nswe] + timeh = timeh[timeh <= 1.0] + count_v = len(timeh) + var = np.append( + np.flip(var), + table[ + sht + + nswe * nsnum + + (nsnum // 2 + snu - 1) * nswe : sht + + nswe * nsnum + + (nsnum // 2 + snu) * nswe + ][:count_v], + ) + time = np.append(np.flip(time), timeh) + elif what == "pcow": + nswe = tabdim[21] + tunit = "s$_w$ [-]" + sht = tabdim[20] - 1 + base = sht + (snu - 1) * nswe + time = table[base : base + nswe] + time = time[time <= 1.0] + count_v = len(time) + var = table[ + sht + + 2 * nswe * nsnum + + (snu - 1) * nswe : sht + + 2 * nswe * nsnum + + snu * nswe + ][:count_v] + else: + tunit = "s$_g$ [-]" + sht = tabdim[23] - 1 + base = sht + (snu - 1) * nswe + time = table[base : base + nswe] + time = time[time <= 1.0] + count_v = len(time) + var = table[ + sht + + 2 * nswe * nsnum + + (snu - 1) * nswe : sht + + 2 * nswe * nsnum + + snu * nswe + ][:count_v] + elif values[:6] == "pcfact" or values[:8] == "permfact": + cap = 6 if values[:6] == "pcfact" else 8 + snu = int(tokens[0][cap:]) if not values in ["pcfact", "permfact"] else 1 + tmp0 = [] + tmp2 = [] + found = False + vec = tokens[0].upper()[:cap] + file_name = _find_keyword(case, vec) + count = 0 + with open(file_name, "r", encoding="utf8") as file: + for row in csv.reader(file, delimiter=" "): + if len(row) > 0: + if row[0] == vec: + found = True + if count == snu: + break + if ( + len(row) > 1 + and row[0].strip() != "--" + and found + and count == snu - 1 + ): + tmp0.append(float(row[0])) + tmp2.append(float(row[1])) + if len(row) > 2 and row[2].strip() == "/": + break + if ( + found + and row[0] == "/" + or len(row) > 2 + and row[2].strip() == "/" + ): + count += 1 + if not tmp2: + plopm_error(f"not found {cli_error_value(f'-v {tokens[0]}')}.") + var = np.array(tmp2) + time = np.array(tmp0) + else: + summary = OpmSummary(f"{case}.SMSPEC") + key = tokens[0].upper() + keys = summary.keys() + if tokens[0] in cfg.summary_mass: + var = summary[key[:-1]] + elif key in summary: + var = summary[key] + else: + plopm_error(f"no {cli_error_value(f'-v {tokens[0]}')} found.") + if len(tokens) > 1: + ops = tokens[1::2] + for index, val in enumerate(tokens[2::2]): + if val.upper() in keys: + other = summary[val.upper()] + else: + other = float(val) + var = _apply_operator(var, other, ops[index]) + if tunit == "Dates": + smsp_dates = 86400 * summary["TIME"] + time = np.array( + [ + summary.start_date + datetime.timedelta(seconds=float(sec)) + for sec in smsp_dates + ] + ) + else: + time = summary["TIME"] * tskl + if tokens[0] in ["fgip", "fgit"]: + vunit = " [sm$^3$]" + elif tokens[0] in cfg.summary_mass: + var *= GAS_DEN_REF + vunit = mass_unit(qskl) + elif tokens[0] in ["time"]: + vunit = " [d]" + return time, var * qskl, tunit, vunit
+ + + +def _find_keyword(case: str, vec: str) -> str: + """Find the deck file containing an OPM keyword. + + Parameters + ---------- + case : str + Simulation-case stem. + vec : str + OPM keyword to locate. + + Returns + ------- + str + DATA or included file containing the keyword. + + """ + include = False + path = "" + parts = case.split("/") + if len(parts) > 1: + path = "/".join(parts[:-1]) + "/" + case_file = case + ".DATA" + includes = [] + with open(case_file, "r", encoding="utf8") as file: + for row in csv.reader(file): + if not row: + continue + val = row[0] + if val == vec: + return case_file + if val == "INCLUDE": + include = True + continue + if include: + name = val.split("/")[0].strip(" ") + if "'" in name: + name = name[1:-1] + full = path + name + if os.path.isfile(full): + includes.append(full) + include = False + for include_file in includes: + with open(include_file, "r", encoding="utf8") as file: + for row in csv.reader(file): + if not row: + continue + if row[0] == vec: + return include_file + files = case_file + if len(includes) > 1: + if len(includes) == 1: + files += f" and {includes[0]}" + else: + files += ", " + files += ", ".join(includes[:-1]) + files += f" and {includes[-1]}" + plopm_error(f"not found keyword {cli_error_value(f'-v {vec}')} " f"in {files}.") + + +def _apply_operator( + var: NDArray[np.float64], other: NDArray[np.float64], op: str +) -> NDArray[np.float64]: + """Apply an arithmetic or comparison operator. + + Parameters + ---------- + var, other : np.ndarray + Left- and right-hand values. + op : str + Arithmetic or comparison operator. + + Returns + ------- + np.ndarray + Operation result. Failed comparisons are NaN. + + """ + if op == "+": + return var + other + if op == "-": + return var - other + if op == "*": + return var * other + if op == "/": + return var / other + mask = ~np.isnan(var) + qmask = ~np.isnan(other) + mask = mask & qmask + if op == "==": + var[mask] = np.where(var[mask] == other[mask], 1.0, np.nan) + elif op == ">=": + var[mask] = np.where(var[mask] >= other[mask], 1.0, np.nan) + elif op == "<=": + var[mask] = np.where(var[mask] <= other[mask], 1.0, np.nan) + elif op == "<": + var[mask] = np.where(var[mask] < other[mask], 1.0, np.nan) + elif op == ">": + var[mask] = np.where(var[mask] > other[mask], 1.0, np.nan) + elif op == "!=": + var[mask] = np.where(var[mask] != other[mask], 1.0, np.nan) + else: + plopm_error(f"unknow operation {cli_error_value(f'-v {op}')}.") + return var + + +
+[docs] +def time_unit(times: str) -> tuple[float, str]: + """Get the conversion and label for a time unit. + + Parameters + ---------- + times : str + Time-unit code or ``"dates"``. + + Returns + ------- + tuple[float, str] + Factor converting OPM days and the axis label. + + """ + if times == "s": + return 86400.0, "Time [seconds]" + if times == "m": + return 1440.0, "Time [minutes]" + if times == "h": + return 24.0, "Time [hours]" + if times == "d": + return 1.0, "Time [days]" + if times == "w": + return 0.14285714285714285, "Time [weeks]" + if times == "y": + return 0.002737909255898758, "Time [years]" + if times == "dates": + return 1, "Dates" + return 86400.0, "Time [seconds]"
+ + + +
+[docs] +def read_csv_grid( + cfg: PlopmConfig, deck: str, n: int +) -> tuple[NDArray, NDArray, int, int, str, str]: + """Read coordinate meshes from a regular CSV grid. + + Parameters + ---------- + cfg : PlopmConfig + CSV column and animation configuration. + deck : str + CSV path without the extension. + n : int + Map index. + + Returns + ------- + tuple + Coordinate meshes, dimensions, and axis names. + + """ + if cfg.gif: + file_name = deck.replace("PLOPM", str(cfg.restart[0])) + else: + file_name = deck + csvv = np.genfromtxt(f"{file_name}.csv", delimiter=",", skip_header=1) + col_x = cfg.csv_columns[n][0] - 1 + col_y = cfg.csv_columns[n][1] - 1 + x0 = csvv[0, col_x] + x1 = csvv[-1, col_x] + y0 = csvv[0, col_y] + y1 = csvv[-1, col_y] + x = x1 + x0 + y = y1 + y0 + mx = round(x / (2.0 * x0)) + my = round(y / (2.0 * y0)) + xname = "x" + yname = "y" + xmx = np.linspace(0, x, mx + 1) + ymy = np.linspace(0, y, my + 1) + return xmx[None, :], ymy[::-1][:, None], mx, my, xname, yname
+ + + +def _apply_filter(porvs: NDArray, other: NDArray, op: str, value: float) -> NDArray: + """Apply a comparison filter to pore-volume values. + + Parameters + ---------- + porvs : np.ndarray + Pore-volume values. + other : np.ndarray + Values tested by the filter. + op : str + Comparison operator. + value : float + Comparison threshold. + + Returns + ------- + np.ndarray + Pore volume where the condition is true and zero elsewhere. + + """ + if op == "==": + mask = other == value + elif op == ">=": + mask = other >= value + elif op == "<=": + mask = other <= value + elif op == "<": + mask = other < value + elif op == ">": + mask = other > value + elif op == "!=": + mask = other != value + else: + plopm_error(f"unknow filter operation {cli_error_value(f'-flt {op}')}.") + return np.where(mask, porvs, 0) + + +
+[docs] +def get_unit(name: str) -> str: + """Get the display unit for a variable. + + Parameters + ---------- + name : str + Variable name. + + Returns + ------- + str + Matplotlib-formatted unit label. + + """ + name_low = name.lower() + if name_low in {"disperc", "depth", "dx", "dy", "dz"}: + return " [m]" + if name_low in {"porv", "fgip", "fgit"}: + return r" [sm$^3$]" + if name_low in {"permx", "permy", "permz"}: + return " [mD]" + if name_low in {"tranx", "trany", "tranz"}: + return " [cP rm$^3$/ (day bar)]" + if name_low in {"pressure", "rpr", "fpr", "fprr", "wbhp"}: + return " [bar]" + return " [-]"
+ + + +
+[docs] +def read_quantity( + deck: str, + data: SimData, + name: str, + step: int, + scale: float, + mass: list[str], + mass_all: list[str], + caprock: list[str], + stress: float, + filters: str, + isgif: bool, + vmin: str, + vmax: str, + cvs: list, +) -> tuple[str, NDArray]: + """Read and transform one spatial or VTK quantity. + + Parameters + ---------- + deck : str + Simulation-case stem or CSV path. + data : SimData + Loaded simulation data. + name : str + Variable name or expression. + step : int + Restart report step. + scale : float + Scale factor applied to derived values. + mass, mass_all, caprock : list[str] + Supported derived-variable groups. + stress : float + Stress coefficient for caprock quantities. + filters : str + Property-filter expression. + isgif : bool + Whether the CSV path contains a restart placeholder. + vmin, vmax : str + Optional value thresholds. + cvs : list + CSV input and column settings. + + Returns + ------- + tuple[str, np.ndarray] + Unit label and quantity values. + + """ + names = name.split(" ") + unit = get_unit(name) + name0_low = names[0] + name0 = name0_low.upper() + if cvs[0]: + if isgif: + file_name = deck.replace("PLOPM", str(step)) + else: + file_name = deck + csvv = np.genfromtxt(f"{file_name}.csv", delimiter=",", skip_header=1) + col = cvs[2] - 1 + values = csvv[:, col] + else: + if data.init.count(name0): + values = np.array(data.init[name0], dtype=float) + if name0_low == "porv": + values = data.active_pv + elif name0_low in ["wells", "faults", "grid"]: + values = np.zeros_like(data.init["SATNUM"]) + elif name0_low in ["index_i", "index_j", "index_k"]: + values = np.array( + _grid_indices(name0_low, data.nx, data.ny, data.nz), dtype=float + ) + values = values[data.porv > 0] + elif data.unrst.count(name0, step): + values = data.unrst[name0, step] + if data.unrst.count("RPORV", step): + if filters: + porv0 = np.array(data.init["PORV"]) + mask = porv0 > 0 + base_rporv = np.array(data.unrst["RPORV", step]) + for value in filters.split("&"): + filte = value.strip().split(" ") + key = filte[0].upper() + if data.init.count(key): + q1 = np.array(data.init[key]) + elif data.unrst.count(key, step): + q1 = np.array(data.unrst[key, step]) + else: + plopm_error( + f"unknow filter quantity {cli_error_value(f'-flt {key}')}." + ) + base_rporv = _apply_filter( + base_rporv, q1, filte[1], float(filte[2]) + ) + data.porv[mask] = base_rporv + else: + data.porv[data.porv > 0] = np.array(data.unrst["RPORV", step]) + elif name0_low in mass_all: + values = _get_mass(data, name0_low, step) * scale + if name0_low in mass: + unit = mass_unit(scale) + elif name0_low in caprock: + values, unit = _get_caprock(data, name0_low, step, stress) + elif name0_low in ["swat", "soil", "sgas"]: + values = _get_saturation(data.unrst, name0_low, step) * scale + else: + plopm_error(f"not found {cli_error_value(f'-v {name0}')}.") + if len(names) > 1: + ops = names[1::2] + for j, val in enumerate(names[2::2]): + if val[0].isdigit() and not val[-1].isdigit(): + q1 = data.unrst[val[1:].upper(), int(val[0])] + elif val[0].isdigit() and val[-1].isdigit(): + q1 = np.full_like(values, float(val)) + elif data.init.count(val.upper()): + q1 = np.array(data.init[val.upper()]) + if val.upper() == "PORV": + q1 = q1[data.porv > 0] + elif val in ["index_i", "index_j", "index_k"]: + q1 = np.array( + _grid_indices(val, data.nx, data.ny, data.nz), + dtype=float, + ) + q1 = q1[data.porv > 0] + elif data.unrst.count(val.upper(), step): + q1 = data.unrst[val.upper(), step] + elif val in mass_all: + q1 = _get_mass(data, val, step) * scale + elif val in caprock: + q1, unit = _get_caprock(data, val, step, stress) + else: + plopm_error(f"not found {cli_error_value(f'-v {val}')}.") + values = _apply_operator(values, q1, ops[j]) + if vmin: + values = np.asarray(values) + values[values < float(vmin)] = np.nan + if vmax: + values = np.asarray(values) + values[values > float(vmax)] = np.nan + return unit, values
+ + + +def _get_saturation(unrst: OpmRestart, name: str, step: int) -> NDArray: + """Derive a missing phase saturation. + + Parameters + ---------- + unrst : OpmRestart + UNRST reader. + name : {"soil", "swat", "sgas"} + Saturation to derive. + step : int + Restart report step. + + Returns + ------- + np.ndarray + Requested phase saturation. + + """ + if unrst.count("SOIL", step): + soil = np.array(unrst["SOIL", step]) + else: + soil = np.array(0) + if unrst.count("SGAS", step): + sgas = np.array(unrst["SGAS", step]) + else: + sgas = np.array(0) + if unrst.count("SWAT", step): + swat = np.array(unrst["SWAT", step]) + else: + swat = np.array(0) + if name == "soil": + return 1 - sgas - swat + if name == "swat": + return 1 - sgas - soil + return 1 - soil - swat + + +def _get_mass(data: SimData, name: str, step: int) -> NDArray: + """Compute component masses and mass fractions. + + Parameters + ---------- + data : SimData + Loaded restart data and pore volume. + name : str + Requested derived variable. + step : int + Restart report step. + + Returns + ------- + np.ndarray + Requested component quantity. + + """ + sgas = np.array(data.unrst["SGAS", step]) + rhog = np.array(data.unrst["GAS_DEN", step]) + rhow = np.array(data.unrst["WAT_DEN", step]) + if data.unrst.count("RSW", step): + rsw = np.array(data.unrst["RSW", step]) + else: + rsw = np.zeros_like(sgas) + if data.unrst.count("RVW", step): + rvw = np.array(data.unrst["RVW", step]) + else: + rvw = np.zeros_like(sgas) + if data.unrst.count("RPORV", step): + rpv = np.array(data.unrst["RPORV", step]) + else: + rpv = data.active_pv + denom_l = rsw + WAT_DEN_REF / GAS_DEN_REF + denom_g = rvw + GAS_DEN_REF / WAT_DEN_REF + x_l_co2 = np.zeros_like(rsw) + x_g_h2o = np.zeros_like(rvw) + mask_l = denom_l != 0 + mask_g = denom_g != 0 + x_l_co2[mask_l] = rsw[mask_l] / denom_l[mask_l] + x_g_h2o[mask_g] = rvw[mask_g] / denom_g[mask_g] + inv_sgas = 1.0 - sgas + inv_xg = 1.0 - x_g_h2o + inv_xl = 1.0 - x_l_co2 + co2_g = inv_xg * sgas * rhog * rpv + co2_d = x_l_co2 * inv_sgas * rhow * rpv + h2o_l = inv_xl * inv_sgas * rhow * rpv + h2o_v = x_g_h2o * sgas * rhog * rpv + return _select_mass(name, co2_g, co2_d, h2o_l, h2o_v, x_l_co2, x_g_h2o) + + +def _select_mass( + name: str, + co2_g: NDArray, + co2_d: NDArray, + h2o_l: NDArray, + h2o_v: NDArray, + x_l_co2: NDArray, + x_g_h2o: NDArray, +) -> NDArray: + """Select a mass or mass-fraction result by name. + + Parameters + ---------- + name : str + Requested derived variable. + co2_g, co2_d : np.ndarray + Free and dissolved CO2 masses. + h2o_l, h2o_v : np.ndarray + Liquid and vapor water masses. + x_l_co2, x_g_h2o : np.ndarray + CO2-in-liquid and water-in-gas mass fractions. + + Returns + ------- + np.ndarray + Selected mass or mass fraction. + + """ + if name == "gasm": + return co2_g + if name == "dism": + return co2_d + if name == "liqm": + return h2o_l + if name == "vapm": + return h2o_v + if name == "h2om": + return h2o_v + h2o_l + if name == "xco2l": + return x_l_co2 + if name == "xh2ov": + return x_g_h2o + if name == "xco2v": + return 1 - x_g_h2o + if name == "xh2ol": + return 1 - x_l_co2 + return co2_g + co2_d + + +def _get_caprock( + data: SimData, name: str, step: int, stress: float +) -> tuple[NDArray, str]: + """Compute a caprock-integrity quantity. + + Parameters + ---------- + data : SimData + Loaded static and restart properties. + name : str + Requested caprock variable. + step : int + Restart report step. + stress : float + Vertical stress coefficient. + + Returns + ------- + tuple[np.ndarray, str] + Computed values and unit label. + + """ + init = data.init + unrst = data.unrst + dz = np.array(init["DZ", 0]) + depth = np.array(init["DEPTH", 0]) + dz_half = 0.5 * dz + dz_corr = 0.5 * dz + if unrst.count("WAT_DEN", 0) and unrst.count("WAT_DEN", step): + den0 = np.array(unrst["WAT_DEN", 0]) + den1 = np.array(unrst["WAT_DEN", step]) + else: + den0 = np.array(1000.0) + den1 = np.array(1000.0) + fac = 9.81 / 1e5 + pz_c0 = fac * dz_corr * den0 + pz_c1 = fac * dz_corr * den1 + pressure0 = np.array(unrst["PRESSURE", 0]) + pressure1 = np.array(unrst["PRESSURE", step]) + limipres = stress * (depth - dz_half) + overpres = limipres - (pressure1 - pz_c1) + limipres -= pressure0 - pz_c0 + objepres = np.zeros_like(overpres) + mask = limipres != 0 + objepres[mask] = overpres[mask] / limipres[mask] + if name == "limipres": + return limipres, " [bar]" + if name == "overpres": + return -overpres, " [bar]" + return objepres, " [-]" + + +
+[docs] +def get_wells(cfg: PlopmConfig, n: int) -> tuple[list, list]: + """Read wells intersecting the selected slice. + + Parameters + ---------- + cfg : PlopmConfig + Case and slice configuration. + n : int + Case index. + + Returns + ------- + tuple[list, list[str]] + Completion intervals grouped by well and the well names. + + """ + wells: list[list[list[int]]] = [] + lwells: list[str] = [] + well_map = {} + haswells = False + sources = False + with open(f"{cfg.cases[0][n]}.DATA", "r", encoding="utf8") as file: + for row in csv.reader(file): + if not row: + continue + tokens = row[0].split() + if not tokens: + continue + key = tokens[0] + if key == "COMPDAT": + haswells = True + continue + if key == "SOURCE": + sources = True + continue + if key == "/": + haswells = False + sources = False + continue + if key.startswith("--"): + continue + if haswells: + if len(tokens) < 5: + continue + wname = tokens[0] + if wname not in well_map: + well_map[wname] = len(lwells) + lwells.append(wname) + wells.append([]) + idx = well_map[wname] + wells[idx].append( + [ + int(tokens[1]) - 1, + int(tokens[2]) - 1, + int(tokens[3]) - 1, + int(tokens[4]) - 1, + ] + ) + elif sources: + if len(tokens) < 3: + continue + wname = tokens[0] + if wname not in well_map: + well_map[wname] = len(lwells) + lwells.append(wname) + wells.append([]) + idx = well_map[wname] + wells[idx].append( + [ + int(tokens[0]) - 1, + int(tokens[1]) - 1, + int(tokens[2]) - 1, + int(tokens[2]) - 1, + ] + ) + if not cfg.global_range: + sld_x = cfg.slice[n][0] + sld_y = cfg.slice[n][1] + sld_z = cfg.slice[n][2] + whow = cfg.slice_mode + for i, wells_list in enumerate(wells): + for j, well in enumerate(wells_list): + if not well: + continue + keep = True + if sld_x[0] > -1: + val = well[0] + if whow == "min": + keep = sld_x[0] <= val < sld_x[1] + else: + keep = val == sld_x[0] + elif sld_y[0] > -1: + val = well[1] + if whow == "min": + keep = sld_y[0] <= val < sld_y[1] + else: + keep = val == sld_y[0] + else: + z0, z1 = well[2], well[3] + if whow == "min": + keep = not (sld_z[1] < z0 or sld_z[0] > z1) + else: + keep = sld_z[0] >= z0 and sld_z[0] <= z1 + if not keep: + wells[i][j] = [] + return wells, lwells
+ + + +
+[docs] +def get_faults(cfg: PlopmConfig, n: int) -> tuple[list, list]: + """Read faults intersecting the selected slice. + + Parameters + ---------- + cfg : PlopmConfig + Case and slice configuration. + n : int + Case index. + + Returns + ------- + tuple[list, list[str]] + Grid segments grouped by fault and the fault names. + + """ + faults: list[list[list[int]]] = [] + lfaults: list[str] = [] + fault_map = {} + hasfaults = False + with open(f"{cfg.cases[0][n]}.DATA", "r", encoding="utf8") as file: + for row in csv.reader(file): + if not row: + continue + tokens = row[0].split() + if not tokens: + continue + key = tokens[0] + if key == "FAULTS": + hasfaults = True + continue + if hasfaults: + if key.startswith("--"): + continue + if "/" in key: + break + if len(tokens) < 7: + continue + fname = key + if fname not in fault_map: + fault_map[fname] = len(lfaults) + lfaults.append(fname) + faults.append([]) + idx = fault_map[fname] + faults[idx].append( + [ + int(tokens[1]) - 1, + int(tokens[3]) - 1, + int(tokens[5]) - 1, + int(tokens[6]) - 1, + ] + ) + if not cfg.global_range: + sld_x = cfg.slice[n][0] + sld_y = cfg.slice[n][1] + sld_z = cfg.slice[n][2] + whow = cfg.slice_mode + for i, flist in enumerate(faults): + for j, fault in enumerate(flist): + if not fault: + continue + keep = True + if sld_x[0] > -1: + val = fault[0] + if whow == "min": + keep = sld_x[0] <= val < sld_x[1] + else: + keep = val == sld_x[0] + elif sld_y[0] > -1: + val = fault[1] + if whow == "min": + keep = sld_y[0] <= val < sld_y[1] + else: + keep = val == sld_y[0] + else: + z0, z1 = fault[2], fault[3] + if whow == "min": + keep = not (sld_z[1] < z0 or sld_z[0] > z1) + else: + keep = sld_z[0] >= z0 and sld_z[0] <= z1 + if not keep: + faults[i][j] = [] + return faults, lfaults
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/terminal.html b/docs/_modules/plopm/utils/terminal.html new file mode 100644 index 0000000..f550585 --- /dev/null +++ b/docs/_modules/plopm/utils/terminal.html @@ -0,0 +1,1009 @@ + + + + + + + + + + plopm.utils.terminal — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.terminal

+# SPDX-FileCopyrightText: 2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+
+"""Format plopm help text and command-line messages.
+
+The module hides deprecated aliases from ``--help``, reports their replacements,
+and applies ANSI colors only when supported by the selected output stream.
+"""
+
+import argparse
+import os
+import sys
+from collections.abc import Sequence
+from typing import NoReturn
+
+DEPRECATED_OPTION_ALIASES = {
+    # Input and output
+    "-csv": "-cc",
+    "--csv": "--csv-columns",
+    "-p": "-fp",
+    "--path": "--flow-path",
+    "--mode": "--format",
+    "--output": "--output-dir",
+    "-save": "-fn",
+    "--save": "--filename",
+    # Spatial and temporal selection
+    "--slide": "--slice",
+    "-tunits": "-tu",
+    "--tunits": "--time-units",
+    "-distance": "-dist",
+    # Filtering, masking, and thresholds
+    "-filter": "-flt",
+    "--vmin": "--min-threshold",
+    "--vmax": "--max-threshold",
+    "-mask": "-mv",
+    "--mask": "--mask-variable",
+    "-maskthr": "-mt",
+    "--maskthr": "--mask-threshold",
+    # Computation and data transformation
+    "-how": "-agg",
+    "--how": "--aggregation",
+    "-a": "-sf",
+    "--adjust": "--scale-factor",
+    "-diff": "-di",
+    "--diff": "--difference-input",
+    "-stress": "-sc",
+    "--stress": "--stress-coefficient",
+    "-dual": "-dg",
+    "--dual": "--dual-grid",
+    # Plot types and statistical representation
+    "-histogram": "-hist",
+    "-ensemble": "-ens",
+    "-bandprop": "-fb",
+    "--bandprop": "--fill-between-style",
+    "-step": "-sp",
+    "--step": "--step-plot",
+    # Figure and subplot layout
+    "-d": "-fs",
+    "--dimensions": "--figsize",
+    "-subfigs": "-sg",
+    "--subfigs": "--subplot-grid",
+    "-cbsfax": "-cbp",
+    "--cbsfax": "--colorbar-position",
+    "-delax": "-rdl",
+    "--delax": "--remove-duplicate-labels",
+    # Titles, labels, and legends
+    "-suptitle": "-st",
+    "-xlabel": "-xl",
+    "-ylabel": "-yl",
+    "-clabel": "-cbl",
+    "--clabel": "--colorbar-label",
+    "-labels": "-llb",
+    "--labels": "--legend-labels",
+    "-loc": "-ll",
+    "--loc": "--legend-location",
+    "-remove": "-hide",
+    "--remove": "--hide-map-elements",
+    # Axes, coordinates, and formatting
+    "-xunits": "-xu",
+    "-yunits": "-yu",
+    "-z": "-asp",
+    "--scale": "--equal-aspect",
+    "-rotate": "-rot",
+    "--rotate": "--rotation",
+    "-translate": "-tr",
+    "--translate": "--translation",
+    "-xformat": "-xf",
+    "-yformat": "-yf",
+    "-xlnum": "-xnt",
+    "--xlnum": "--xtick-count",
+    "-ylnum": "-ynt",
+    "--ylnum": "--ytick-count",
+    # Color scales and styling
+    "-b": "-cl",
+    "--bounds": "--clim",
+    "-log": "-clog",
+    "--log": "--color-log",
+    "-clogthks": "-clt",
+    "--clogthks": "--color-log-ticks",
+    "-global": "-gr",
+    "--global": "--global-range",
+    "-cformat": "-cbf",
+    "--cformat": "--colorbar-format",
+    "-cnum": "-cbn",
+    "--cnum": "--colorbar-tick-count",
+    "-cticks": "-cbt",
+    "--cticks": "--colorbar-ticks",
+    "--lw": "--linewidth",
+    "-e": "-ls",
+    "-axgrid": "-ag",
+    "--axgrid": "--axis-grid",
+    "-facecolor": "-fc",
+    "-ncolor": "-ic",
+    "--ncolor": "--inactive-color",
+    "-grid": "-ge",
+    "--grid": "--grid-edges",
+    "-f": "-fz",
+    "--size": "--fontsize",
+    # VTK output
+    "-vtkformat": "-vf",
+    "--vtkformat": "--vtk-format",
+    "-vtknames": "-vn",
+    "--vtknames": "--vtk-names",
+    # GIF output
+    "-interval": "-gi",
+    "--interval": "--gif-interval",
+    "-loop": "-gl",
+    "--loop": "--gif-loop",
+    # Information and diagnostics
+    "-printv": "-lv",
+    "--printv": "--list-variables",
+}
+ANSI_BOLD_RED = "1;31"
+ANSI_BOLD_YELLOW = "1;33"
+ANSI_BOLD_GREEN = "1;32"
+ANSI_BOLD_BLUE = "1;34"
+ANSI_BOLD_MAGENTA = "1;35"
+ANSI_YELLOW = "1;33"
+ANSI_GREEN = "1;32"
+ANSI_CYAN = "36"
+ANSI_RED = "31"
+ANSI_BLUE = "1;34"
+
+
+
+[docs] +class PlopmHelpFormatter(argparse.ArgumentDefaultsHelpFormatter): + """Argparse formatter that hides deprecated option aliases. + + Current options retain the standard + :class:`argparse.ArgumentDefaultsHelpFormatter` layout and default values. + + """ + + def _format_action_invocation( + self, + action: argparse.Action, + ) -> str: + """Format one argparse action using current option names. + + Parameters + ---------- + action : argparse.Action + Action whose option invocation is displayed in CLI help. + + Returns + ------- + str + Formatted invocation with deprecated aliases omitted. + + """ + if not action.option_strings: + return super()._format_action_invocation(action) + + original_options = action.option_strings + visible_options = [ + option + for option in original_options + if option not in DEPRECATED_OPTION_ALIASES + ] + + if not visible_options: + return super()._format_action_invocation(action) + + try: + action.option_strings = visible_options + return super()._format_action_invocation(action) + finally: + action.option_strings = original_options
+ + + +
+[docs] +def warn_deprecated_options(argv: Sequence[str]) -> None: + """Warn once for each deprecated option in an argument list. + + Parameters + ---------- + argv : Sequence[str] + Command-line arguments, excluding or including the executable name. + + """ + reported: set[str] = set() + + for argument in argv: + option = argument.partition("=")[0] + + if option not in DEPRECATED_OPTION_ALIASES or option in reported: + continue + + replacement = DEPRECATED_OPTION_ALIASES[option] + + plopm_warning( + f"option {cli_deprecated_value(option)} is deprecated and will be " + f"removed in the next release; use {cli_current_value(replacement)} " + "instead" + ) + reported.add(option)
+ + + +def _supports_color(stream: object = sys.stderr) -> bool: + """Check whether an output stream supports ANSI colors. + + Parameters + ---------- + stream : object, default: sys.stderr + Output stream to inspect. + + Returns + ------- + bool + ``True`` for an interactive stream unless colors are disabled by + ``NO_COLOR`` or ``TERM=dumb``. + + """ + return ( + hasattr(stream, "isatty") + and stream.isatty() + and os.environ.get("NO_COLOR") is None + and os.environ.get("TERM") != "dumb" + ) + + +def _colorize( + text: str, + code: str, + stream: object = sys.stderr, +) -> str: + """Wrap text in an ANSI color sequence when supported. + + Parameters + ---------- + text : str + Text to format. + code : str + ANSI Select Graphic Rendition code. + stream : object, default: sys.stderr + Output stream used to determine color support. + + Returns + ------- + str + Colored text, or the original text when colors are unavailable. + + """ + if not _supports_color(stream): + return text + return f"\033[{code}m{text}\033[0m" + + +
+[docs] +def cli_deprecated_value(value: str) -> str: + """Format a deprecated CLI option or value. + + Parameters + ---------- + value : str + Option or value to display. + + Returns + ------- + str + Quoted value with deprecated-option styling when supported. + + """ + return _colorize(repr(value), ANSI_YELLOW)
+ + + +
+[docs] +def cli_current_value(value: str) -> str: + """Format a current CLI option or value. + + Parameters + ---------- + value : str + Option or value to display. + + Returns + ------- + str + Quoted value with current-option styling when supported. + + """ + return _colorize(repr(value), ANSI_GREEN)
+ + + +
+[docs] +def cli_error_value(value: str) -> str: + """Format an invalid CLI option or value. + + Parameters + ---------- + value : str + Option or value to display. + + Returns + ------- + str + Quoted value with error styling when supported. + + """ + return _colorize(repr(value), ANSI_RED)
+ + + +
+[docs] +def cli_info_value(value: str) -> str: + """Format an informational CLI option or value. + + Parameters + ---------- + value : str + Option or value to display. + + Returns + ------- + str + Quoted value with informational styling when supported. + + """ + return _colorize(repr(value), ANSI_BLUE)
+ + + +
+[docs] +def plopm_error(message: str) -> NoReturn: + """Raise a fatal command-line error. + + Parameters + ---------- + message : str + Error message displayed after the plopm label. + + Raises + ------ + SystemExit + Always raised with the formatted error message. + + """ + label = _colorize("error", ANSI_BOLD_RED) + raise SystemExit(f"{plopm_name()}: {label}: {message}")
+ + + +
+[docs] +def plopm_warning(message: str) -> None: + """Display a non-fatal command-line warning. + + Parameters + ---------- + message : str + Warning message displayed on standard error. + + """ + label = _colorize("warning", ANSI_BOLD_YELLOW) + print(f"{plopm_name()}: {label}: {message}", file=sys.stderr)
+ + + +
+[docs] +def plopm_info(message: str) -> None: + """Display an informational command-line message. + + Parameters + ---------- + message : str + Message displayed on standard output. + + """ + label = _colorize("info", ANSI_BOLD_BLUE, sys.stdout) + print(f"{plopm_name()}: {label}: {message}")
+ + + +
+[docs] +def plopm_tip(message: str) -> None: + """Display a command-line suggestion. + + Parameters + ---------- + message : str + Suggestion displayed on standard output. + + """ + label = _colorize("tip", ANSI_BOLD_MAGENTA, sys.stdout) + print(f"{plopm_name(sys.stdout)}: {label}: {message}")
+ + + +
+[docs] +def plopm_success(output_dir: str, filenames: list[str]) -> None: + """Display the generated output location and filenames. + + Parameters + ---------- + output_dir : str + Directory containing the generated files. + filenames : list[str] + Generated filenames. + + """ + label = _colorize("success", ANSI_BOLD_GREEN, sys.stdout) + if not filenames: + plopm_error("Unreachable code executed") + elif len(filenames) == 1: + print(f"{plopm_name()}: {label}: {output_dir}/{filenames[0]}") + elif len(filenames) <= 5: + print(f"{plopm_name()}: {label}") + print(f" Output directory: {output_dir}") + print(f" Files: {', '.join(filenames)}") + else: + print(f"{plopm_name()}: {label}") + print(f" Output directory: {output_dir}") + print(f" Files ({len(filenames)}):") + for filename in filenames: + print(f" - {filename}")
+ + + +
+[docs] +def plopm_name(stream: object = sys.stderr) -> str: + """Format the plopm program name. + + Parameters + ---------- + stream : object, default: sys.stderr + Output stream used to determine color support. + + Returns + ------- + str + Program name with gradient colors when supported. + + """ + characters = [ + ("p", "36"), + ("l", "36"), + ("o", "35"), + ("p", "36"), + ("m", "36"), + ] + return "".join( + _colorize(character, color, stream) for character, color in characters + )
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/write_oned.html b/docs/_modules/plopm/utils/write_oned.html new file mode 100644 index 0000000..c684f75 --- /dev/null +++ b/docs/_modules/plopm/utils/write_oned.html @@ -0,0 +1,1177 @@ + + + + + + + + + + plopm.utils.write_oned — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.write_oned

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=W3301,W0123,R0912,R0915,R0914,R1702,W0611,R0913,R0917,C0302,C0115,R0916,E1102
+
+"""Create one-dimensional plots and tabular output from OPM results.
+
+The module reads summary vectors, grid-derived series, and optional CSV data.
+It also supports ensemble statistics, subplot layouts, and PNG or CSV output.
+"""
+
+import os
+import warnings
+
+import matplotlib.pyplot as plt
+import numpy as np
+from matplotlib.axes import Axes
+from matplotlib.figure import Figure
+from numpy.typing import NDArray
+from scipy.interpolate import interp1d
+from scipy.stats import lognorm, norm
+
+from plopm.config.config import PlopmConfig
+from plopm.utils.readers import read_series
+from plopm.utils.terminal import cli_info_value, plopm_info
+
+
+
+[docs] +def make_plots(cfg: PlopmConfig) -> list[str]: + """Create the requested one-dimensional plots and CSV files. + + Parameters + ---------- + cfg : PlopmConfig + Initialized plotting configuration. + + Returns + ------- + list[str] + Names of the generated files. + + """ + generated_files: list[str] = [] + + deckn = _get_deck_name(cfg.cases[0][0]) + fig, _ = plt.subplots(1, 1) + if ( + cfg.ensemble == 0 + and not cfg.subplot_grid[0] + and len(cfg.cases[0]) < len(cfg.variables) + ): + cfg.cases[0] = [cfg.cases[0][0]] * len(cfg.variables) + if len(cfg.linewidth[0]) < len(cfg.variables): + cfg.linewidth[0] = [cfg.linewidth[0][0]] * len(cfg.variables) + cfg.linewidth = [cfg.linewidth[0]] * len(cfg.variables) + if len(cfg.colors[0]) < len(cfg.variables): + cfg.colors[0] = [cfg.colors[0][0]] * len(cfg.variables) + cfg.colors = [cfg.colors[0]] * len(cfg.variables) + if len(cfg.linestyle[0]) < len(cfg.variables): + cfg.linestyle[0] = [cfg.linestyle[0][0]] * len(cfg.variables) + cfg.linestyle = [cfg.linestyle[0]] * len(cfg.variables) + if cfg.subplot_grid[0]: + plt.close() + fig, axes = plt.subplots( + int(cfg.subplot_grid[0]), int(cfg.subplot_grid[1]), layout="compressed" + ) + for j, quan in enumerate(cfg.variables): + k = j + if not cfg.subplot_grid[0]: + plt.close() + fig, axes = plt.subplots(1, 1, layout="compressed") + axes = np.array([axes]) + k = 0 + axis = axes.flat[k] + axis.grid(int(cfg.axis_grid[j])) + if cfg.ensemble > 0: + tunit, vunit, min_t, max_t, min_v, max_v = _plot_ensemble(cfg, axes) + else: + ylow = 0 if cfg.ylog[j] == "1" else -np.inf + xlow = 0 if cfg.xlog[j] == "1" else -np.inf + min_t, max_t, min_v, max_v = 0, 0, 0, 0 + for i, name in enumerate(cfg.cases[j]): + jj = j + if len(cfg.variables) == len(cfg.cases[0]) and not cfg.subplot_grid[0]: + jj = i + quan = cfg.variables[i] + time, var, tunit, vunit = read_series( + cfg, name, quan, cfg.time_units[jj], float(cfg.scale_factor[jj]), i + ) + label = _get_label(cfg, name, jj, i) + if cfg.step_plot: + axis.step( + time, + var, + color=cfg.colors[jj][i % len(cfg.colors[jj])], + ls=cfg.linestyle[jj][i % len(cfg.linestyle[jj])], + label=label, + lw=float(cfg.linewidth[jj][i]), + ) + elif cfg.histogram[0]: + ij = i + j * len(cfg.cases[j]) + if ( + len(cfg.variables) == len(cfg.cases[0]) + and not cfg.subplot_grid[0] + ): + ij = i + hist = cfg.histogram[ij].split(",") + mean = np.nanmean(var) + std = np.nanstd(var) + plopm_info( + f"histogram: {cli_info_value(f'mean={mean:.6E}')}, " + f"{cli_info_value(f'std={std:.6E}')}" + ) + if not cfg.legend_labels[0][0]: + label += f" (mean={mean:.3E}, std={std:.3E})" + counts, bins, _ = axis.hist( + var, + int(hist[0]), + color=cfg.colors[jj][(i + k) % len(cfg.colors[jj])], + label=label, + ) + if len(hist) > 1: + xnorm = np.linspace(bins[0], bins[-1], 1000) + if hist[1] == "norm": + norm_pdf = norm.pdf(xnorm, mean, std) + norm_max = np.max(norm_pdf) + if norm_max > 0: + axis.plot( + xnorm, + np.max(counts) * norm_pdf / norm_max, + color=cfg.colors[jj][(i + k) % len(cfg.colors[jj])], + ) + elif hist[1] == "lognorm": + if mean > 0: + a = 1 + (std / mean) ** 2 + s = np.sqrt(np.log(a)) + scale = mean / np.sqrt(a) + dist = lognorm(s, 0, scale) + dist_pdf = dist.pdf(xnorm) + dist_max = np.max(dist_pdf) + plopm_info( + f"distribution: " + f"{cli_info_value(f'lognorm({s:.6E}, 0, {scale:.6E})')}" + ) + if dist_max > 0: + axis.plot( + xnorm, + np.max(counts) * dist_pdf / dist_max, + color=cfg.colors[jj][ + (i + k) % len(cfg.colors[jj]) + ], + ) + else: + axis.plot( + time, + var, + color=cfg.colors[jj][i % len(cfg.colors[jj])], + ls=cfg.linestyle[jj][i % len(cfg.linestyle[jj])], + label=label, + lw=float(cfg.linewidth[jj][i]), + ) + min_t, max_t, min_v, max_v = _update_limits( + time, var, tunit, min_t, max_t, min_v, max_v, xlow, ylow, i == 0 + ) + axis.set_ylabel(quan + vunit) + if not cfg.histogram[0]: + if min_v != max_v: + axis.set_ylim([min_v, max_v]) + else: + axis.set_ylabel("Histogram of " + quan + vunit) + if not cfg.remove_duplicate_labels or k + int(cfg.subplot_grid[1]) >= len( + cfg.variables + ): + axis.set_xlabel(tunit) + if cfg.xlabel[0]: + axis.set_xlabel(cfg.xlabel[j]) + if cfg.ylabel[0]: + axis.set_ylabel(cfg.ylabel[j]) + xlabels = np.empty(0) + ylabels = np.empty(0) + if len(cfg.xlim[0]) > 1: + axis.set_xlim([float(cfg.xlim[j][0][1:]), float(cfg.xlim[j][1][:-1])]) + xlabels = np.linspace( + float(cfg.xlim[j][0][1:]), + float(cfg.xlim[j][1][:-1]), + int(cfg.xtick_count[j]), + ) + elif tunit != "Dates" and not cfg.histogram[0]: + if min_v != max_v: + axis.set_xlim([min_t, max_t]) + xlabels = np.linspace(min_t, max_t, int(cfg.xtick_count[j])) + if len(cfg.ylim[0]) > 1: + axis.set_ylim([float(cfg.ylim[j][0][1:]), float(cfg.ylim[j][1][:-1])]) + ylabels = np.linspace( + float(cfg.ylim[j][0][1:]), + float(cfg.ylim[j][1][:-1]), + int(cfg.ytick_count[j]), + ) + elif not cfg.histogram[0]: + if min_v != max_v: + axis.set_ylim([min_v, max_v]) + ylabels = np.linspace(min_v, max_v, int(cfg.ytick_count[j])) + if cfg.xlog[j] == "1": + axis.set_xscale("log") + else: + if tunit != "Dates": + if cfg.xformat[0]: + _set_formatted_ticks(axis, xlabels, cfg.xformat[j], "x") + elif not cfg.histogram[0]: + axis.set_xticks(xlabels) + if cfg.ylog[j] == "1": + axis.set_yscale("log") + else: + if cfg.yformat[0]: + _set_formatted_ticks(axis, ylabels, cfg.yformat[j], "y") + elif not cfg.histogram[0]: + axis.set_yticks(ylabels) + if cfg.legend_location[j] != "empty": + axis.legend(loc=cfg.legend_location[j]) + if cfg.title[j] != "0" and cfg.hide_map_elements[3] == 0: + axis.set_title(cfg.title[j]) + if cfg.remove_duplicate_labels and k + int(cfg.subplot_grid[1]) < len( + cfg.variables + ): + axis.tick_params(axis="x", which="both", bottom=False, labelbottom=False) + if len(cfg.variables) == len(cfg.cases[0]) and not cfg.subplot_grid[0]: + if cfg.csv: + generated_files.append(_save_summary_csv(cfg, deckn, var, quan, j)) + return generated_files + generated_files.append(_save_summary_png(cfg, deckn, quan, j, fig)) + return generated_files + if ( + not cfg.subplot_grid[0] and len(cfg.variables) != len(cfg.cases[0]) + ) or j == len(cfg.variables) - 1: + if ( + len(cfg.legend_location) == j + 2 + and j != 0 + and len(axes.flat) - len(cfg.variables) > 0 + ): + for jj, qua in enumerate(cfg.variables[: cfg.ncolors]): + for i, name in enumerate(cfg.cases[jj]): + time, var, tunit, vunit = read_series( + cfg, + name, + qua, + cfg.time_units[jj], + float(cfg.scale_factor[jj]), + i, + ) + label = _get_label(cfg, name, jj, i) + if cfg.sensor or cfg.layer or cfg.distance[0]: + axes.flat[-1].plot( + time, + var, + color=cfg.colors[jj][i], + ls=cfg.linestyle[jj][i], + label=label, + lw=float(cfg.linewidth[jj][i]), + ) + else: + axes.flat[-1].step( + time, + var, + color=cfg.colors[jj][i], + ls=cfg.linestyle[jj][i], + label=label, + lw=float(cfg.linewidth[jj][i]), + ) + axes.flat[-1].axis("off") + axes.flat[-1].legend(loc=cfg.legend_location[-1]) + for line in axes.flat[-1].get_lines(): + line.remove() + for o in range(len(axes.flat) - len(cfg.variables) - 1): + fig.delaxes(axes.flat[-2 - o]) + else: + for o in range(len(axes.flat) - len(cfg.variables)): + fig.delaxes(axes.flat[-1 - o]) + generated_files.append(_save_summary_png(cfg, deckn, quan, j, fig)) + plt.close() + return list(dict.fromkeys(generated_files))
+ + + +def _clean_name(name: str) -> str: + """Convert a variable expression to a filename-safe stem. + + Parameters + ---------- + name : str + Variable expression or proposed filename stem. + + Returns + ------- + str + Name with operators and separators replaced. + + """ + name = name.replace(" / ", "_over_") + name = name.replace(" ", "") + name = name.replace(":", "-") + return name + + +def _get_deck_name(name: str) -> str: + """Get a display name from a case or include-file path. + + Parameters + ---------- + name : str + Case path or include filename. + + Returns + ------- + str + Lowercase basename without an ``.inc`` extension. + + """ + deckn = name.split("/")[-1].lower() + if ".inc" in deckn: + deckn = deckn[:-4] + return deckn + + +def _get_label(cfg: PlopmConfig, name: str, var_index: int, name_index: int) -> str: + """Select the legend label for a plotted series. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration containing ensemble cases and plot styles. + name : str + Simulation-case path. + var_index : int + Index of the plotted variable. + name_index : int + Index of the case within the variable group. + + Returns + ------- + str + User-defined label or a label derived from the case path. + + """ + label = name + if len(name.split("/")) > 1: + label = name.split("/")[-2] + "/" + name.split("/")[-1] + if cfg.legend_labels[0][0]: + label = cfg.legend_labels[var_index][name_index] + return label + + +def _update_limits( + time: NDArray, + var: NDArray, + tunit: str, + min_t: float, + max_t: float, + min_v: float, + max_v: float, + xlow: float, + ylow: float, + first: bool, +) -> tuple[float, float, float, float]: + """Update the data limits from one plotted series. + + Parameters + ---------- + time, var : np.ndarray + Time coordinates and variable values. + tunit : str + Time-axis label. ``"Dates"`` selects date handling. + min_t, max_t : float + Current time limits. + min_v, max_v : float + Current variable limits. + xlow, ylow : float + Lower bounds used to exclude invalid logarithmic values. + first : bool + Whether this is the first series included in the limits. + + Returns + ------- + tuple[float, float, float, float] + Updated ``(min_t, max_t, min_v, max_v)`` limits. + + """ + valid_var = var[var > ylow] + valid_time = time[time > xlow] if tunit != "Dates" else time + if valid_var.size == 0: + current_min_v = min_v if not first else 0 + else: + current_min_v = np.min(valid_var) + current_max_v = np.nanmax(var) if np.any(~np.isnan(var)) else max_v + current_max_t = np.max(time) + if tunit != "Dates": + current_min_t = np.min(valid_time) if valid_time.size > 0 else min_t + else: + current_min_t = time[0] + if first: + return current_min_t, current_max_t, current_min_v, current_max_v + return ( + min(min_t, current_min_t), + max(max_t, current_max_t), + min(min_v, current_min_v), + max(max_v, current_max_v), + ) + + +def _set_formatted_ticks( + axis: Axes, labels: NDArray, value_format: str, axis_name: str +) -> None: + """Set explicitly formatted ticks on one axis. + + Parameters + ---------- + axis : matplotlib.axes.Axes + Axis to update. + labels : np.ndarray + Numeric tick locations. + value_format : str + Python format specification for each label. + axis_name : {"x", "y"} + Coordinate axis to update. + + """ + formatted_labels = [format(value, value_format) for value in labels] + ticks = [float(label) for label in formatted_labels] + if axis_name == "x": + axis.set_xticks(ticks) + axis.set_xticklabels(formatted_labels) + else: + axis.set_yticks(ticks) + axis.set_yticklabels(formatted_labels) + + +def _save_summary_csv( + cfg: PlopmConfig, deckn: str, var: NDArray, quan: str, index: int +) -> str: + """Write non-NaN summary values to a CSV file. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration containing ensemble cases and plot styles. + deckn : str + Case name used in the default filename. + var : np.ndarray + Values to write. + quan : str + Variable expression used in the default filename. + index : int + Plot index used to select a custom filename. + + Returns + ------- + str + Name of the generated CSV file. + + """ + text = [f"{val}\n" for val in var if not np.isnan(val)] + name = _clean_name(f"{deckn}_{quan}") + if cfg.filename[index]: + name = cfg.filename[index] + filename = f"{name}.csv" + with open( + os.path.join(cfg.output_dir, filename), + "w", + encoding="utf8", + ) as file: + file.write("".join(text)) + return filename + + +def _save_summary_png( + cfg: PlopmConfig, + deckn: str, + quan: str, + index: int, + fig: Figure, +) -> str: + """Save a summary figure as a PNG file. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration containing ensemble cases and plot styles. + deckn : str + Case name used in the default filename. + quan : str + Variable expression used in the default filename. + index : int + Plot index used to select filename and resolution settings. + fig : matplotlib.figure.Figure + Figure to save. + + Returns + ------- + str + Name of the generated PNG file. + + """ + name = _clean_name(f"{deckn}_{quan}") + filename = f"{cfg.filename[index] if cfg.filename[index] else name}.png" + fig.savefig( + os.path.join(cfg.output_dir, filename), + bbox_inches="tight", + dpi=int(cfg.dpi[index]), + ) + return filename + + +def _plot_ensemble( + cfg: PlopmConfig, axes: Axes | np.ndarray +) -> tuple[str, str, float, float, float, float]: + """Plot ensemble statistics for the first requested variable. + + Each realization is interpolated to a shared coordinate array. Depending on + ``cfg.ensemble``, the function plots the mean, a one-standard-deviation band, + the bounding realizations, or both. + + Parameters + ---------- + cfg : PlopmConfig + Initialized configuration containing ensemble cases and plot styles. + axes : matplotlib.axes.Axes or np.ndarray + Axis, or array of axes, on which to draw the ensemble. + + Returns + ------- + tuple[str, str, float, float, float, float] + Time unit, value unit, and ``(min_t, max_t, min_v, max_v)`` limits. + + """ + axis = axes if isinstance(axes, Axes) else np.ravel(axes)[0] + thetime, timeeval = np.array([0]), np.array([0]) + min_v, max_v = np.inf, -np.inf + hyst = 1 + var_name = cfg.variables[0] + if ( + var_name[:3] in ["krw", "krg"] + or var_name[:4] + in [ + "krow", + "krog", + "pcow", + "pcog", + "pcwg", + ] + and var_name[-1] == "h" + ): + hyst = 2 + for hyst_index in range(hyst): + for names_index, names in enumerate(cfg.cases): + label = cfg.case_labels[0][names_index] + " (mean)" + if len(label.split("/")) > 1: + label = label.split("/")[-2] + "/" + label.split("/")[-1] + if cfg.legend_labels[0][0]: + label = cfg.legend_labels[names_index][0] + tmp = [] + for name_index, name in enumerate(names): + time, var, tunit, vunit = read_series( + cfg, + name, + var_name, + cfg.time_units[0], + float(cfg.scale_factor[0]), + name_index, + ) + rng = int(1.0 * len(time) / hyst) + time = time[hyst_index * rng : (hyst_index + 1) * rng] + var = var[hyst_index * rng : (hyst_index + 1) * rng] + if time.size > thetime.size: + thetime = time.copy() + if tunit == "Dates": + time = np.array([value.timestamp() for value in time], dtype=float) + if time.size > timeeval.size: + timeeval = time.copy() + else: + timeeval = thetime + tmp.append(interp1d(time, var, bounds_error=False)) + values = np.array([value(timeeval) for value in tmp]) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message="Mean of empty slice") + warnings.filterwarnings("ignore", message="Degrees of freedom <= 0") + means = np.nanmean(values, axis=0) + stdev = np.nanstd(values, axis=0) + plot_label = label if hyst_index == hyst - 1 else None + axis.plot( + thetime, + means, + color=cfg.colors[0][names_index], + ls=cfg.linestyle[0][names_index], + label=plot_label, + lw=float(cfg.linewidth[0][names_index]), + ) + if cfg.ensemble in [1, 3]: + if cfg.fill_between_style: + band_properties = cfg.fill_between_style.split(",") + color = band_properties[2 * names_index] + alpha = float(band_properties[2 * names_index + 1]) + else: + color = cfg.colors[0][names_index] + alpha = 0.2 + lower_band = means - stdev + upper_band = means + stdev + axis.fill_between( + thetime, lower_band, upper_band, color=color, alpha=alpha + ) + if np.any(~np.isnan(lower_band)): + min_v = min(min_v, np.nanmin(lower_band)) + if np.any(~np.isnan(upper_band)): + max_v = max(max_v, np.nanmax(upper_band)) + if cfg.ensemble in [2, 3]: + ensemble_index = len(cfg.cases) + names_index + maxs = np.nansum(values + means, axis=1) + mins = np.nansum(values - means, axis=1) + maxs = np.where(maxs == np.max(maxs))[0][0] + mins = np.where(mins == np.min(mins))[0][0] + labell = names[mins] + " (lower)" + labelu = names[maxs] + " (upper)" + if cfg.legend_labels[0][0]: + labell = cfg.legend_labels[names_index][1] + labelu = cfg.legend_labels[names_index][2] + lower_label = labell if hyst_index == hyst - 1 else None + upper_label = labelu if hyst_index == hyst - 1 else None + axis.plot( + thetime, + values[mins], + color=cfg.colors[0][ensemble_index], + ls=cfg.linestyle[0][ensemble_index], + label=lower_label, + lw=float(cfg.linewidth[0][names_index]), + ) + axis.plot( + thetime, + values[maxs], + color=cfg.colors[0][ensemble_index], + ls=cfg.linestyle[0][ensemble_index], + label=upper_label, + lw=float(cfg.linewidth[0][names_index]), + ) + if np.any(~np.isnan(values[mins])): + min_v = min(min_v, np.nanmin(values[mins])) + if np.any(~np.isnan(values[maxs])): + max_v = max(max_v, np.nanmax(values[maxs])) + min_t, max_t = thetime[0], thetime[-1] + return tunit, vunit, min_t, max_t, min_v, max_v +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/write_twod.html b/docs/_modules/plopm/utils/write_twod.html new file mode 100644 index 0000000..54e7d9e --- /dev/null +++ b/docs/_modules/plopm/utils/write_twod.html @@ -0,0 +1,2652 @@ + + + + + + + + + + plopm.utils.write_twod — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.write_twod

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=W3301,W0123,R0912,R0915,R0914,R1702,W0611,R0913,R0917,C0302,C0115,R0916,E1102
+
+"""Create two-dimensional maps and animations from OPM results.
+
+The module prepares grid geometry, maps three-dimensional properties onto
+selected slices, and writes PNG or GIF output with optional masks, differences,
+well and fault overlays, and shared color limits.
+"""
+
+import datetime
+import sys
+from collections.abc import Iterable
+from contextlib import nullcontext
+from typing import Any
+
+import colorcet  # noqa: F401  # registers colorcet colormaps with matplotlib
+import matplotlib
+import matplotlib.pyplot as plt
+import matplotlib.ticker as mticker
+import numpy as np
+from alive_progress import alive_bar
+from matplotlib import animation, colors
+from matplotlib.animation import FuncAnimation, writers
+from matplotlib.artist import Artist
+from matplotlib.axes import Axes
+from matplotlib.cm import ScalarMappable
+from matplotlib.figure import Figure
+from matplotlib.ticker import LogFormatter
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+from mpl_toolkits.axes_grid1.axes_divider import AxesDivider
+from numpy.typing import NDArray
+
+from plopm.config.config import PlopmConfig, SimData
+from plopm.utils.mapping import (
+    get_xy_slice,
+    get_xz_slice,
+    get_yz_slice,
+    map_xy,
+    map_xz,
+    map_yz,
+    transform_grid,
+)
+from plopm.utils.readers import (
+    get_faults,
+    get_wells,
+    read_case,
+    read_csv_grid,
+    read_quantity,
+    time_unit,
+)
+from plopm.utils.terminal import cli_error_value, plopm_error
+
+
+
+[docs] +def make_maps(cfg: PlopmConfig) -> list[str]: + """Create the requested spatial maps and animations. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + + Returns + ------- + list[str] + Names of the generated PNG and GIF files. + + """ + generated_files: list[str] = [] + skip = 0 + if ( + cfg.subplot_grid[0] + and len(cfg.variables) > 1 + and len(cfg.restart) == 1 + and len(cfg.cases[0]) == 1 + ): + skip = 1 + if cfg.subplot_grid[0]: + fig, axis = _create_figure(int(cfg.subplot_grid[0]), int(cfg.subplot_grid[1])) + sub1 = int(cfg.subplot_grid[1]) + else: + fig, axis = _create_figure(1, 1, "compressed") + sub1 = 1 + if cfg.subplot_grid[0] and cfg.gif and len(cfg.cases[0]) > 1: + _, _, _, cmin, cmax, diffa = _get_clim(cfg) + maska = _get_masks(cfg) if cfg.mask_variable else [] + deckd = _case_name(cfg.difference_input) if cfg.difference_input else "" + fig, axis = _create_figure( + int(cfg.subplot_grid[0]), int(cfg.subplot_grid[1]), "compressed" + ) + axes = _normalize_axis(axis) + data, xc, yc, named, slice_title, slice_name, mx, my, xname, yname = ( + _prepare_map(cfg, cfg.cases[0][0], 0) + ) + original_loc, cb = _prepare_colorbars(axes) + _delete_extra_axes(axes, len(cfg.cases[0]), fig) + im_ani = animation.FuncAnimation( + fig, + _draw_frame, + fargs=( + cfg.cases[0][0], + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + 0, + data, + xc, + yc, + skip, + sub1, + mx, + my, + xname, + yname, + ), + frames=len(data.steps), + interval=cfg.gif_interval, + blit=False, + repeat=False, + ) + generated_files.append( + _save_animation( + cfg, im_ani, cfg.filename[0] if cfg.filename[0] else cfg.variables[0] + ) + ) + elif cfg.subplot_grid[0] and cfg.gif and len(cfg.variables) > 1: + data, xc, yc, cmin, cmax, diffa = _get_clim(cfg) + deckd = _case_name(cfg.difference_input) if cfg.difference_input else "" + data, xc, yc, named, slice_title, slice_name, mx, my, xname, yname = ( + _prepare_map(cfg, cfg.cases[0][0], 0) + ) + maska = _get_masks(cfg) if cfg.mask_variable else [] + if len(data.steps) > 1: + fig, axis = _create_figure( + int(cfg.subplot_grid[0]), int(cfg.subplot_grid[1]) + ) + axes = _normalize_axis(axis) + plt.tight_layout(pad=1.7) + original_loc, cb = _prepare_colorbars(axes) + _delete_extra_axes(axes, len(cfg.variables), fig) + im_ani = animation.FuncAnimation( + fig, + _draw_frame, + fargs=( + cfg.cases[0][0], + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + 0, + data, + xc, + yc, + skip, + sub1, + mx, + my, + xname, + yname, + ), + frames=len(data.steps), + interval=cfg.gif_interval, + blit=False, + repeat=False, + ) + generated_files.append( + _save_animation(cfg, im_ani, cfg.filename[0] if cfg.filename[0] else named) + ) + else: + _, _, _, cmin, cmax, diffa = _get_clim(cfg) + maska = _get_masks(cfg) if cfg.mask_variable else [] + deckd = _case_name(cfg.difference_input) if cfg.difference_input else "" + data, xc, yc, named, slice_title, slice_name, mx, my, xname, yname = ( + _prepare_map(cfg, cfg.cases[0][0], 0) + ) + for n, var in enumerate(cfg.variables): + if len(data.steps) > 1: + if cfg.subplot_grid[0]: + fig, axis = _create_figure( + int(cfg.subplot_grid[0]), int(cfg.subplot_grid[1]) + ) + else: + fig, axis = _create_figure(1, 1) + if not cfg.subplot_grid[0] and not cfg.gif: + plt.close() + fig, axis = _create_figure(1, 1, "tight") + axes = _normalize_axis(axis) + original_loc, cb = _prepare_colorbars(axes) + if len(data.steps) > 1: + _delete_extra_axes(axes, len(data.steps), fig) + if cfg.gif and len(data.steps) > 1: + im_ani = animation.FuncAnimation( + fig, + _draw_frame, + fargs=( + cfg.cases[0][0], + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + n, + data, + xc, + yc, + skip, + sub1, + mx, + my, + xname, + yname, + ), + frames=len(data.steps), + interval=cfg.gif_interval, + blit=False, + repeat=False, + ) + name = f"{cfg.filename[0] if cfg.filename[0] else named + '_' + var}" + generated_files.append(_save_animation(cfg, im_ani, name)) + else: + if len(cfg.cases[0]) > 1: + _delete_extra_axes(axes, len(cfg.cases[0]), fig) + if len(data.steps) > 1 and len(cfg.cases[0]) == len(data.steps): + if not cfg.subplot_grid[0]: + fig, axis = _create_figure(1, 1) + axes = _normalize_axis(axis) + original_loc, cb = _prepare_colorbars(axes) + _draw_frame( + 0, + cfg.cases[0][0], + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + n, + data, + xc, + yc, + skip, + sub1, + mx, + my, + xname, + yname, + ) + else: + for t, _ in enumerate(data.steps): + if not cfg.subplot_grid[0]: + plt.close() + fig, axis = _create_figure(1, 1) + axes = _normalize_axis(axis) + original_loc, cb = _prepare_colorbars(axes) + _draw_frame( + t, + cfg.cases[0][0], + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + n, + data, + xc, + yc, + skip, + sub1, + mx, + my, + xname, + yname, + ) + return list(dict.fromkeys(generated_files))
+ + + +def _prepare_map( + cfg: PlopmConfig, deck: str, n: int +) -> tuple[SimData, NDArray, NDArray, str, str, str, int, int, str, str]: + """Prepare simulation data and coordinates for one map. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + deck : str + Simulation-case stem or CSV input path. + n : int + Case or map index used to select configuration values. + + Returns + ------- + tuple + Simulation data, coordinate meshes, case and slice labels, mesh + dimensions, and coordinate-axis names. + + """ + if cfg.csv_columns[n][0]: + xc, yc, mx, my, xname, yname = read_csv_grid(cfg, deck, n) + slice_title, slice_name = "", "" + data = SimData(steps=cfg.restart) + else: + data = read_case( + deck, cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters, n + ) + slice_value = cfg.slice[n] + if slice_value[0][0] != -2: + xc, yc, slice_title, slice_name, mx, my, xname, yname = get_yz_slice( + cfg, data, n + ) + elif slice_value[1][0] != -2: + xc, yc, slice_title, slice_name, mx, my, xname, yname = get_xz_slice( + cfg, data, n + ) + else: + xc, yc, slice_title, slice_name, mx, my, xname, yname = get_xy_slice( + cfg, data, n + ) + if int(cfg.rotation[n]) != 0 or cfg.translation[n] != ["[0", "0]"]: + xc, yc = transform_grid(cfg, n, xc, yc) + return ( + data, + xc, + yc, + deck.rsplit("/", 1)[-1].lower(), + slice_title, + slice_name, + mx, + my, + xname, + yname, + ) + + +def _create_figure( + rows: int = 1, + columns: int = 1, + layout: str | None = None, +) -> tuple[Figure, Axes]: + """Create a Matplotlib figure and axes. + + Parameters + ---------- + rows, columns : int, default: 1 + Number of subplot rows and columns. + layout : str, optional + Matplotlib layout engine. + + Returns + ------- + tuple + Created figure and axes. + + """ + plt.close() + if layout: + fig, axes = plt.subplots(rows, columns, layout=layout) + else: + fig, axes = plt.subplots(rows, columns) + return fig, axes + + +def _normalize_axis(axes: Axes | NDArray[Any]) -> NDArray: + """Return axes as a one-dimensional-compatible array. + + Parameters + ---------- + axes : matplotlib.axes.Axes or np.ndarray + Axes returned by Matplotlib. + + Returns + ------- + np.ndarray + Array containing the supplied axes. + + """ + if isinstance(axes, np.ndarray): + return axes + return np.array([axes]) + + +def _prepare_colorbars(axes: NDArray[Any]) -> tuple[list[Any], list[str]]: + """Initialize colorbar state for each subplot. + + Parameters + ---------- + axes : np.ndarray + Subplot axes. + + Returns + ------- + tuple[list, list] + Original axes locators and empty colorbar slots. + + """ + original_loc, cb = [], [] + for axis in axes.flat: + original_loc.append(axis.get_axes_locator()) + cb.append("") + return original_loc, cb + + +def _delete_extra_axes(axes: NDArray[Any], keep: int, fig: Figure) -> None: + """Remove unused subplot axes. + + Parameters + ---------- + axes : np.ndarray + Subplot axes. + keep : int + Number of axes to retain. + fig : matplotlib.figure.Figure + Figure containing the axes. + + """ + for o in range(max(0, len(axes.flat) - keep)): + axis_to_remove = axes.flat[-1 - o] + if axis_to_remove in fig.axes: + fig.delaxes(axis_to_remove) + + +def _save_animation(cfg: PlopmConfig, im_ani: FuncAnimation, name: str) -> str: + """Save a Matplotlib animation as a GIF. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + im_ani : matplotlib.animation.FuncAnimation + Animation to save. + name : str + Output filename without extension. + + Returns + ------- + str + Name of the generated GIF file. + + """ + filename = f"{name}.gif" + output_path = f"{cfg.output_dir}/{filename}" + if cfg.gif_loop or not writers.is_available("ffmpeg"): + im_ani.save(output_path) + else: + im_ani.save(output_path, extra_args=["-loop", "-1"]) + return filename + + +def _map_values( + cfg: PlopmConfig, + data: SimData, + var: str, + values: NDArray, + slice_index: int, + map_index: int, + mx: int, + my: int, + use_csv: bool = False, +) -> NDArray: + """Map quantity values onto the selected two-dimensional slice. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + data : SimData + Loaded simulation data. + var : str + Variable name. + values : np.ndarray + Values in active-cell or CSV order. + slice_index, map_index : int + Indices selecting the slice and its mapping settings. + mx, my : int + Mapped grid dimensions. + use_csv : bool, default: False + Whether values already use the two-dimensional CSV layout. + + Returns + ------- + np.ndarray + Values arranged on the selected map. + + """ + if use_csv: + quaa = np.asarray(values).copy() + elif cfg.slice[slice_index][0][0] != -2: + quaa = map_yz(cfg, data, var, values, map_index, mx, my) + elif cfg.slice[slice_index][1][0] != -2: + quaa = map_xz(cfg, data, var, values, map_index, mx, my) + else: + quaa = map_xy(cfg, data, var, values, map_index, mx, my) + return quaa + + +def _get_clim( + cfg: PlopmConfig, +) -> tuple[SimData, NDArray, NDArray, list[float], list[float], list[NDArray]]: + """Determine color limits and cached difference maps. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + + Returns + ------- + tuple + Last loaded simulation data, coordinate meshes, color minima and + maxima, and cached difference arrays. + + """ + cmin, cmax = [float("inf")], [float("-inf")] + diffa: list[NDArray] = [] + xc, yc = np.empty(0), np.empty(0) + if (cfg.rst_range and cfg.png and not cfg.subplot_grid[0]) or ( + cfg.clim[0][0] and not cfg.difference_input + ): + return SimData(), xc, yc, cmin, cmax, diffa + + if cfg.restart[0] == -1 and cfg.gif: + data = read_case( + cfg.cases[0][0], cfg.gif, cfg.vtk, cfg.variables, cfg.restart, cfg.filters + ) + else: + data = SimData(steps=cfg.restart) + if cfg.difference_input: + var = cfg.variables[0] + for t, _ in enumerate(data.steps): + data, xc, yc, _, _, _, mx, my, _, _ = _prepare_map( + cfg, cfg.difference_input, 1 + ) + _, values = read_quantity( + cfg.difference_input, + data, + var, + data.steps[t], + float(cfg.scale_factor[0]), + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters[0], + cfg.gif, + cfg.min_threshold[0], + cfg.max_threshold[0], + cfg.csv_columns[0], + ) + quaa = _map_values(cfg, data, var, values, 1, 1, mx, my) + diffa.append(quaa.copy()) + if len(cfg.variables) == len(cfg.cases[0]) and len(cfg.cases[0]) > 1: + for m, var in enumerate(cfg.variables): + cmin.append(cmin[-1]) + cmax.append(cmax[-1]) + for t, _ in enumerate(data.steps): + data, xc, yc, _, _, _, mx, my, _, _ = _prepare_map( + cfg, cfg.cases[0][m], m + ) + _, values = read_quantity( + cfg.cases[0][m], + data, + var, + data.steps[t], + float(cfg.scale_factor[m]), + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters[0], + cfg.gif, + cfg.min_threshold[m], + cfg.max_threshold[m], + cfg.csv_columns[0], + ) + quaa = _map_values(cfg, data, var, values, m, m, mx, my) + _apply_diff_and_log(cfg, diffa, quaa, m, t) + _update_color_range(quaa, cmin, cmax) + else: + for m, var in enumerate(cfg.variables): + cmin.append(cmin[-1]) + cmax.append(cmax[-1]) + for n, deck in enumerate(cfg.cases[0]): + for t, _ in enumerate(data.steps): + data, xc, yc, _, _, _, mx, my, _, _ = _prepare_map(cfg, deck, n) + _, values = read_quantity( + deck, + data, + var, + data.steps[t], + float(cfg.scale_factor[m]), + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters[n], + cfg.gif, + cfg.min_threshold[m], + cfg.max_threshold[m], + cfg.csv_columns[n], + ) + quaa = _map_values( + cfg, data, var, values, n, n, mx, my, cfg.csv_columns[n][0] + ) + _apply_diff_and_log(cfg, diffa, quaa, m, t) + _update_color_range(quaa, cmin, cmax) + return data, xc, yc, cmin, cmax, diffa + + +def _apply_diff_and_log( + cfg: PlopmConfig, + diffa: list[NDArray], + quaa: NDArray, + var_index: int, + restart_index: int, +) -> None: + """Apply difference and logarithmic transformations in place. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + diffa : list[np.ndarray] + Mapped difference values. + quaa : np.ndarray + Mapped values to transform. + var_index : int + Variable index. + restart_index : int + Restart-step index used to select a cached difference map. + + """ + if cfg.difference_input: + quaa -= diffa[restart_index] + if int(cfg.color_log[var_index]) == 1: + quaa[quaa <= 0] = np.nan + + +def _update_color_range(quaa: NDArray, cmin: list[float], cmax: list[float]) -> None: + """Update the current finite color range. + + Parameters + ---------- + quaa : np.ndarray + Mapped values included in the color range. + cmin : list[float] + Color minima. + cmax : list[float] + Color minima. + + """ + if np.any(~np.isnan(quaa)): + cmin[-2] = min(cmin[-2], np.nanmin(quaa)) + cmax[-2] = max(cmax[-2], np.nanmax(quaa)) + + +def _get_masks(cfg: PlopmConfig) -> list[NDArray]: + """Read and map masks for all configured cases. + + Parameters + ---------- + cfg : PlopmConfig + Initialized map configuration. + + Returns + ------- + list[np.ndarray] + Mapped mask arrays. + + """ + maska = [] + var = cfg.mask_variable + for n, deck in enumerate(cfg.cases[0]): + data, _, _, _, _, _, mx, my, _, _ = _prepare_map(cfg, deck, n) + _, values = read_quantity( + deck, + data, + var, + 0, + float(cfg.scale_factor[0]), + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters[n], + cfg.gif, + cfg.min_threshold[0], + cfg.max_threshold[0], + cfg.csv_columns[n], + ) + maska.append(_map_values(cfg, data, var, values, n, n, mx, my)) + return maska + + +def _case_name(deck: str) -> str: + """Get a lowercase case name from a path. + + Parameters + ---------- + deck : str + Simulation-case path. + + Returns + ------- + str + Final path component in lowercase. + + """ + if len(deck.split("/")) > 1: + return deck.split("/")[-1].lower() + return deck.lower() + + +def _draw_frame( + t: int, + deck: str, + fig: Figure, + axes: Any, + original_loc: list[Any], + cb: list[str], + cmin: list[float], + cmax: list[float], + maska: list[Any], + diffa: list[NDArray], + named: str, + deckd: str, + slice_title: str, + slice_name: str, + cfg: PlopmConfig, + generated_files: list[str], + n: int, + data: SimData, + xc: NDArray, + yc: NDArray, + skip: int, + sub1: int, + mx: int, + my: int, + xname: str, + yname: str, +) -> Iterable[Artist]: + """Draw all maps belonging to one animation frame. + + This dispatcher selects cases, variables, restart steps, and subplot + positions before delegating each map to :func:`draw_map`. + + Parameters + ---------- + t : int + Animation-frame or restart-step index. + deck : str + Primary simulation-case stem. + fig : matplotlib.figure.Figure + Figure receiving the maps. + axes : matplotlib.axes.Axes or np.ndarray + Target axes. + original_loc, cb : list + Original axes locators and active colorbars. + cmin, cmax : list[float] + Color limits for each variable or map. + maska, diffa : list + Mapped masks and cached difference arrays. + named, deckd : str + Display names for the primary and difference cases. + slice_title, slice_name : str + Human-readable slice descriptions. + cfg : PlopmConfig + Initialized map configuration. + generated_files : list[str] + Generated filenames updated during rendering. + n : int + Current variable or case index. + data : SimData + Loaded simulation data. + xc, yc : np.ndarray + Coordinate meshes. + skip, sub1 : int + Subplot-control values. + mx, my : int + Mapped grid dimensions. + xname, yname : str + Coordinate-axis names. + + Returns + ------- + list[matplotlib.artist.Artist] + Empty artist list required by the animation callback. + + """ + k = t + if not cfg.subplot_grid[0]: + k = 0 + elif len(data.steps) == 1: + k = n + if cfg.subplot_grid[0] and len(cfg.cases[0]) > 1: + show_progress = sys.stdout.isatty() + if show_progress: + bar_ctx = alive_bar(len(cfg.cases[0]), bar="fish") + else: + bar_ctx = nullcontext() + with bar_ctx as bar_animation: + if len(cfg.variables) > 1: + cmax = [np.max(cmax)] * len(cmax) + cmin = [np.min(cmin)] * len(cmin) + for nn, deckl in enumerate(cfg.cases[0]): + if show_progress: + bar_animation() + ( + data, + xc, + yc, + named, + slice_title, + slice_name, + mx, + my, + xname, + yname, + ) = _prepare_map(cfg, deckl, nn) + _draw_map( + deckl, + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + data, + t, + nn, + nn, + xc, + yc, + sub1, + mx, + my, + xname, + yname, + ) + else: + for nn, deckl in enumerate(cfg.cases[0]): + if show_progress: + bar_animation() + ( + data, + xc, + yc, + named, + slice_title, + slice_name, + mx, + my, + xname, + yname, + ) = _prepare_map(cfg, deckl, nn) + if len(data.steps) > 1 and len(cfg.cases[0]) == len(data.steps): + _draw_map( + deckl, + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + data, + nn, + 0, + nn, + xc, + yc, + sub1, + mx, + my, + xname, + yname, + ) + else: + _draw_map( + deckl, + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + data, + t, + 0, + nn, + xc, + yc, + sub1, + mx, + my, + xname, + yname, + ) + elif cfg.subplot_grid[0] and len(cfg.variables) > 1 and skip == 0: + show_progress = sys.stdout.isatty() + if show_progress: + bar_ctx = alive_bar(len(cfg.variables), bar="fish") + else: + bar_ctx = nullcontext() + with bar_ctx as bar_animation: + for nn, _ in enumerate(cfg.variables): + if show_progress: + bar_animation() + _draw_map( + deck, + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + data, + t, + nn, + nn, + xc, + yc, + sub1, + mx, + my, + xname, + yname, + ) + else: + _draw_map( + deck, + fig, + axes, + original_loc, + cb, + cmin, + cmax, + maska, + diffa, + named, + deckd, + slice_title, + slice_name, + cfg, + generated_files, + data, + t, + n, + k, + xc, + yc, + sub1, + mx, + my, + xname, + yname, + ) + return [] + + +def _set_axis( + fig: Figure, + axes: Any, + cfg: PlopmConfig, + data: SimData, + name: str, + n: int, + t: int, + k: int, + n_s: int, + unit: str, + xc: NDArray, + yc: NDArray, + extinf: float, + named: str, + deckd: str, + defcol: bool, + slice_title: str, + feature_id: int, +) -> None: + """Configure labels, limits, ticks, and annotations for a map axis. + + Parameters + ---------- + fig : matplotlib.figure.Figure + Figure containing the map. + axes : matplotlib.axes.Axes or np.ndarray + Map axes. + cfg : PlopmConfig + Initialized map configuration. + data : SimData + Loaded simulation data. + name : str + Variable name. + n, t, k, n_s : int + Variable, restart, subplot, and slice indices. + unit : str + Variable unit label. + xc, yc : np.ndarray + Coordinate meshes. + extinf : float + Padding added to map extents. + named, deckd : str + Display names for the primary and difference cases. + defcol : bool + Whether default categorical colors are used. + slice_title : str + Human-readable slice description. + feature_id : int + Number assigned to the active well or fault feature. + + """ + unrst = data.unrst + nx = data.nx + ny = data.ny + nz = data.nz + actind = data.active_idx + restart = data.steps + porv = data.active_pv + axis = axes.flat[k] + name_lower = name.lower() + is_discrete_num = ( + "num" in name + and (cfg.colormaps[n] in cfg.disc_colormaps or defcol) + and cfg.discrete + ) + namet, time = name, "" + if cfg.time_units[0] == "dates": + date_values = unrst["INTEHEAD", restart[t]] + date = datetime.date( + date_values[66], + date_values[65], + date_values[64], + ) + time = f" {date}" + elif cfg.time_units[0] == "empty": + pass + else: + tskl, tunit = time_unit(cfg.time_units[0]) + tunit = tunit[5:] + if unrst and unrst.count("DOUBHEAD", 0): + time = f" {tskl*unrst['DOUBHEAD', restart[t]][0]:.0f} {tunit}" + elif cfg.time_units[0] in ["s", "m", "h", "d", "w", "y"]: + time = f" {restart[t]:.0f} {tunit}" + else: + time = f" {restart[t]:.0f} [{cfg.time_units[0]}]" + if cfg.equal_aspect: + axis.axis("scaled") + extra = "" + if name_lower == "porv": + extra = f", sum={np.sum(porv):.3e}" + elif name_lower in cfg.mass_vars and cfg.difference_input: + extra = f", |sum|={extinf:.3e} {unit}" + elif name_lower in cfg.mass_vars: + extra = f", sum={extinf:.3e} {unit}" + elif cfg.difference_input: + extra = f", |sum|={extinf:.3e}" + elif cfg.variables[0] in ["wells", "faults"]: + time = "" + namet = f"Total no. {name} = {feature_id-1}, " + elif is_discrete_num: + time = "" + namet = "" + if cfg.csv_columns[n][0]: + tslice = "" + elif cfg.variables[0] in ["wells", "faults"] or is_discrete_num: + tslice = slice_title[2:] + else: + tslice = slice_title + if ( + cfg.subplot_grid[0] + and len(cfg.cases[0]) > 1 + and cfg.title[k] == "0" + and cfg.hide_map_elements[3] == 0 + ): + if name_lower == "porv": + named += f" (total porv={np.sum(data.porv)})" + axis.set_title(named) + if k == 0 and cfg.suptitle != "0": + fig.suptitle(f"{time[1:]}") + elif cfg.subplot_grid[0] and len(cfg.variables) > 1 and cfg.title[k] == "0": + if k == 0 and cfg.suptitle != "0": + fig.suptitle(f"{named}{time}") + elif ( + cfg.gif + and len(cfg.variables) == 1 + and cfg.title[k] == "0" + and cfg.hide_map_elements[3] == 0 + ): + if cfg.difference_input: + axis.set_title(f"{named}-{deckd}{time}") + else: + axis.set_title(f"{named}{time}") + elif ( + cfg.gif + and len(cfg.variables) == 1 + and cfg.title[k] != "0" + and cfg.hide_map_elements[3] == 0 + ): + if not cfg.csv_columns[n][0]: + axis.set_title(f"{cfg.title[k]} {time}") + else: + axis.set_title(f"{cfg.title[k]}") + fig.suptitle(time) + elif ( + len(restart) > 1 + and cfg.subplot_grid[0] + and len(cfg.cases[0]) == 1 + and cfg.title[k] == "0" + and cfg.hide_map_elements[3] == 0 + ): + axis.set_title(f"{unrst['DOUBHEAD', restart[t]][0]} days") + if k == 0 and cfg.suptitle != "0": + if cfg.difference_input: + fig.suptitle(f"{named}-{deckd}") + else: + fig.suptitle(f"{named}") + elif cfg.hide_map_elements[3] == 0 and cfg.title[k] == "0": + if cfg.difference_input: + axis.set_title(f"{named}-{deckd}" + tslice + extra + time) + else: + axis.set_title(namet + tslice + extra + time) + elif cfg.subplot_grid[0] and len(cfg.cases[0]) > 1: + if k == 0 and cfg.suptitle != "0": + if cfg.gif and cfg.csv_columns[n][0]: + fig.suptitle(f"{restart[t]} {cfg.time_units[0]}") + elif unrst: + fig.suptitle(f"{unrst['DOUBHEAD', restart[t]][0]} days") + else: + fig.suptitle(f"{restart[t]} {cfg.time_units[0]}") + if name_lower == "grid" and cfg.hide_map_elements[3] == 0 and cfg.title[k] == "0": + axis.set_title( + f"Grid = [{nx},{ny},{nz}], " + + f"Total no. active cells = {np.max(actind)+1}" + ) + if cfg.title[k] != "0" and cfg.hide_map_elements[3] == 0 and not cfg.gif: + axis.set_title(cfg.title[k]) + if cfg.slice[n_s][2][0] == -2 and not axis.yaxis_inverted(): + axis.invert_yaxis() + if len(cfg.xlim[n]) > 1: + axis.set_xlim([float(cfg.xlim[n][0][1:]), float(cfg.xlim[n][1][:-1])]) + xlabels = np.linspace( + float(cfg.xlim[n][0][1:]) * cfg.xscale, + float(cfg.xlim[n][1][:-1]) * cfg.xscale, + int(cfg.xtick_count[n]), + ) + else: + xlabels = np.linspace( + np.min(xc) * cfg.xscale, + np.max(xc) * cfg.xscale, + int(cfg.xtick_count[n]), + ) + _set_axis_ticks( + axis, "x", xlabels, cfg.xscale, cfg.xformat[n], cfg.hide_map_elements[1] + ) + if len(cfg.ylim[n]) > 1: + axis.set_ylim([float(cfg.ylim[n][0][1:]), float(cfg.ylim[n][1][:-1])]) + ylabels = np.linspace( + float(cfg.ylim[n][0][1:]) * cfg.yscale, + float(cfg.ylim[n][1][:-1]) * cfg.yscale, + int(cfg.ytick_count[n]), + ) + else: + ylabels = np.linspace( + np.min(yc) * cfg.yscale, + np.max(yc) * cfg.yscale, + int(cfg.ytick_count[n]), + ) + _set_axis_ticks( + axis, "y", ylabels, cfg.yscale, cfg.yformat[n], cfg.hide_map_elements[0] + ) + + +def _formatted_ticks( + values: NDArray, + scale: float, + value_format: str, +) -> tuple[list[float], list[str]]: + """Format scaled tick locations and labels. + + Parameters + ---------- + values : np.ndarray + Unscaled tick values. + scale : float + Coordinate scale factor. + value_format : str + Python format specification. + + Returns + ------- + tuple[list[float], list[str]] + Scaled tick locations and formatted labels. + + """ + labels = [format(value, value_format) for value in values] + ticks = [float(label) / scale for label in labels] + return ticks, labels + + +def _set_axis_ticks( + axis: Any, + axis_name: str, + labels: NDArray, + scale: float, + value_format: str, + remove_axis: int, +) -> None: + """Set formatted ticks on one coordinate axis. + + Parameters + ---------- + axis : matplotlib.axes.Axes or np.ndarray + Map axes. + axis_name : {"x", "y"} + Coordinate axis to update. + labels : np.ndarray + Tick values before scaling. + scale : float + Coordinate scale factor. + value_format : str + Python format specification. + remove_axis : int + Nonzero when the selected axis is hidden. + + """ + if axis_name == "x": + if value_format and remove_axis == 0: + ticks, ticklabels = _formatted_ticks(labels, scale, value_format) + axis.set_xticks(ticks) + axis.set_xticklabels(ticklabels) + elif remove_axis == 0: + axis.set_xticks(labels / scale) + if scale != 1: + axis.set_xticklabels(labels) + else: + if value_format and remove_axis == 0: + ticks, ticklabels = _formatted_ticks(labels, scale, value_format) + axis.set_yticks(ticks) + axis.set_yticklabels(ticklabels) + elif remove_axis == 0: + axis.set_yticks(labels / scale) + if scale != 1: + axis.set_yticklabels(labels) + + +def _draw_map( + deck: str, + fig: Figure, + axes: Any, + original_loc: list[Any], + cb: list[Any], + cmin: list[float], + cmax: list[float], + maska: list[Any], + diffa: list[NDArray], + named: str, + deckd: str, + slice_title: str, + slice_name: str, + cfg: PlopmConfig, + generated_files: list[str], + data: SimData, + t: int, + n: int, + k: int, + xc: NDArray, + yc: NDArray, + sub1: int, + mx: int, + my: int, + xname: str, + yname: str, +) -> None: + """Draw and optionally save one spatial map. + + Parameters + ---------- + deck : str + Simulation-case stem. + fig : matplotlib.figure.Figure + Figure receiving the map. + axes : matplotlib.axes.Axes or np.ndarray + Target axes. + original_loc, cb : list + Original axes locators and active colorbars. + cmin, cmax : list[float] + Configured color limits. + maska, diffa : list + Mapped masks and cached difference arrays. + named, deckd : str + Display names for the primary and difference cases. + slice_title, slice_name : str + Human-readable slice descriptions. + cfg : PlopmConfig + Initialized map configuration. + generated_files : list[str] + Generated filenames updated when a PNG is saved. + data : SimData + Loaded simulation data. + t, n, k : int + Restart-step, variable, and subplot indices. + xc, yc : np.ndarray + Coordinate meshes. + sub1 : int + Number of subplot columns. + mx, my : int + Mapped grid dimensions. + xname, yname : str + Coordinate-axis names. + + """ + var = cfg.variables[n] + unit, values = read_quantity( + deck, + data, + var, + data.steps[t], + float(cfg.scale_factor[n]), + cfg.mass_vars, + cfg.mass_vars + cfg.mass_fracs, + cfg.caprock_vars, + cfg.stress_coefficient, + cfg.filters[k], + cfg.gif, + cfg.min_threshold[n], + cfg.max_threshold[n], + cfg.csv_columns[k], + ) + n_s, feature_id, features = 0, 1, None + labels: list[str] = [] + if cfg.subplot_grid[0] and len(cfg.cases[0]) > 1: + n_s = k + if cfg.csv_columns[k][0]: + quaa = values + else: + if cfg.variables[0] == "wells": + features, labels = get_wells(cfg, k) + elif cfg.variables[0] == "faults": + features, labels = get_faults(cfg, k) + feature_id = len(labels) + 1 + if cfg.slice[n_s][0][0] != -2: + quaa = map_yz(cfg, data, var, values, k, mx, my, features, feature_id) + elif cfg.slice[n_s][1][0] != -2: + quaa = map_xz(cfg, data, var, values, k, mx, my, features, feature_id) + else: + quaa = map_xy(cfg, data, var, values, k, mx, my, features, feature_id) + if cfg.difference_input: + quaa -= diffa[t] + if cfg.mask_variable: + mask = maska[k] + maxv = np.nanmax(mask) + mask_condition = quaa < cfg.mask_threshold + quaa[mask_condition] = -cmax[n] * (maxv - mask[mask_condition]) / (maxv - 1) + if cfg.csv: + text = [f"{val}\n" for val in quaa if not np.isnan(val)] + name = _clean_name(f"{named}_{var}_{slice_name}_t{data.steps[t]}") + if cfg.filename[n]: + name = cfg.filename[n] + filename = f"{name}.csv" + with open( + f"{cfg.output_dir}/{filename}", + "w", + encoding="utf8", + ) as file: + file.write("".join(text)) + generated_files.append(filename) + return + if var in cfg.mass_vars and cfg.difference_input: + extinf = np.nansum(np.abs(quaa)) + elif var in cfg.mass_vars: + extinf = np.sum(quaa[~np.isnan(quaa)]) + elif cfg.difference_input: + extinf = np.nansum(np.abs(quaa)) + else: + extinf = np.empty(0) + ntick = 3 + ncolor = var + " " + unit + defcol, temp, cmap = True, "tab20", matplotlib.colormaps.get_cmap("tab20") + if cfg.colormaps[n] in plt.colormaps(): + defcol = False + cmap = matplotlib.colormaps.get_cmap(cfg.colormaps[n]) + temp = cfg.colormaps[n] + if var not in ("wells", "grid", "faults"): + valid_maps = quaa[~np.isnan(quaa)] + if ( + len(cfg.cases[0]) > 1 + and cfg.subplot_grid[0] + or len(cfg.variables) > 1 + and cfg.subplot_grid[0] + or len(data.steps) > 1 + and cfg.subplot_grid[0] + and len(cfg.cases[0]) == 1 + or cfg.gif + and not cfg.subplot_grid[0] + or int(cfg.color_log[n]) == 1 + ): + minc = cmin[n] + maxc = cmax[n] + elif not cfg.global_range and valid_maps.size > 0: + minc = np.min(valid_maps) + maxc = np.max(valid_maps) + elif valid_maps.size > 0: + values = np.asarray(values) + valid_quan = values[~np.isnan(values)] + if valid_quan.size > 0: + minc = np.min(valid_quan) + maxc = np.max(valid_quan) + else: + minc = 0 + maxc = 0 + else: + minc = 0 + maxc = 0 + if cfg.clim[n][0]: + minc = float(cfg.clim[n][0][1:]) + maxc = float(cfg.clim[n][1][:-1]) + elif cfg.difference_input and int(cfg.color_log[n]) == 0: + minmax = max(abs(maxc), abs(minc)) + minc = -minmax + maxc = minmax + if maxc == minc: + ntick = 1 + elif ( + "num" in var + and (cfg.colormaps[n] in cfg.disc_colormaps or defcol) + and cfg.discrete + and (minc.is_integer() and maxc.is_integer()) + ): + ntick = int(maxc - minc + 1) + if cfg.mask_variable: + minc = -maxc + elif var in ["faults", "wells"]: + minc = 1 + maxc = feature_id + else: + minc = 1 + maxc = 1 + nlc = ntick + if cfg.colorbar_tick_count[n] and ntick > 1: + ntick = int(cfg.colorbar_tick_count[n]) + if cfg.colorbar_label: + ncolor = cfg.colorbar_label + shc = 0.0 + if abs(minc) < sys.float_info.epsilon: + minc = 0 + if ("num" in var and temp in cfg.disc_colormaps and cfg.discrete) or ( + defcol and temp != "nipy_spectral" + ): + if maxc == minc: + shc = 2.0 + from_list = matplotlib.colors.LinearSegmentedColormap.from_list + cmap = from_list( + "custom", + matplotlib.colormaps[temp](range(int(minc), int(minc) + nlc + int(shc))), + nlc, + ) + if ntick == 2: + shc = (maxc - minc) / 2.0 + elif minc == 0 and "num" not in var and var != "mpi_rank" or cfg.mask_variable: + shc = 0 + else: + shc = 0.5 + if defcol: + temp0 = [] + for values in cfg.colormaps[n].split(" "): + if values[0] == "#": + temp0.append(values) + else: + temp0.append([]) + for color in values.split(";"): + if color.isnumeric(): + temp0[-1].append(float(color) / 255.0) + else: + plopm_error( + f"Color given in {cli_error_value(f'-c {cfg.colormaps[n]}')} not found." + ) + cmap = colors.ListedColormap(temp0) + if cfg.inactive_color != "w": + cmap = cmap.with_extremes(bad=cfg.inactive_color) + axis = axes.flat[k] + if len(cfg.grid_edges) > 1: + if var == "grid": + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + facecolors="none", + edgecolors=cfg.grid_edges[0], + lw=float(cfg.grid_edges[1]), + ) + elif int(cfg.color_log[n]) == 0: + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + shading="flat", + cmap=cmap, + edgecolors=cfg.grid_edges[0], + lw=float(cfg.grid_edges[1]), + ) + else: + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + shading="flat", + cmap=cmap, + norm=colors.LogNorm(vmin=minc, vmax=maxc), + edgecolors=cfg.grid_edges[0], + lw=float(cfg.grid_edges[1]), + ) + else: + if var == "grid": + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + facecolors="none", + edgecolors="black", + lw=0.001, + ) + elif int(cfg.color_log[n]) == 0: + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + shading="flat", + cmap=cmap, + ) + else: + imag = axis.pcolormesh( + xc, + yc, + quaa.reshape(my, mx), + shading="flat", + cmap=cmap, + norm=colors.LogNorm(vmin=minc, vmax=maxc), + ) + if cfg.subplot_grid[0] and cfg.gif and len(cfg.variables) > 1 and cb[k] != "": + axes, cb = _remove_colorbar(axes, original_loc, cb, k) + if cfg.subplot_grid[0] and cfg.gif and len(cfg.cases[0]) > 1 and cb[k] != "": + axes, cb = _remove_colorbar(axes, original_loc, cb, k) + if ( + not cfg.subplot_grid[0] + and cb[k] != "" + and cfg.gif + and cfg.hide_map_elements[2] == 0 + ): + axes, cb = _remove_colorbar(axes, original_loc, cb, k) + divider = make_axes_locatable(axis) + if cfg.mask_variable: + vect = np.linspace( + 0, + maxc, + ntick, + endpoint=True, + ) + else: + vect = np.linspace( + minc, + maxc, + ntick, + endpoint=True, + ) + frmt = "{:" + cfg.cb_formats[n] + "}" + + def formatter(value: float, _: Any) -> str: + """Format a colorbar value. + + Parameters + ---------- + value : float + Colorbar value. + _ : Any + Unused Matplotlib tick position. + + Returns + ------- + str + Formatted colorbar label. + + """ + return frmt.format(value) + + if not cfg.mask_variable: + if int(cfg.color_log[n]) == 1: + pass + else: + for i, val in enumerate(vect): + if abs(float(frmt.format(val))) == 0: + vect[i] = 0 + if i == 0: + minc = 0 + if var not in ("wells", "grid", "faults"): + if int(cfg.color_log[n]) == 0: + if len(data.steps) > 1 and cfg.subplot_grid[0] and len(cfg.cases[0]) == 1: + if cfg.colorbar_position[0] != -1: + cb[0] = fig.colorbar( + imag, + cax=fig.add_axes(cfg.colorbar_position), + ticks=vect, + label=ncolor, + format=( + mticker.FixedFormatter(cfg.colorbar_ticks[n]) + if cfg.colorbar_ticks[n] + else formatter + ), + shrink=0.2, + location="top", + ) + elif not cfg.subplot_grid[0] or len(cfg.cases[0]) == 1: + cb[k] = fig.colorbar( + imag, + cax=divider.append_axes("right", size="2%", pad=0.05), + orientation="vertical", + ticks=vect, + label=ncolor, + format=( + mticker.FixedFormatter(cfg.colorbar_ticks[n]) + if cfg.colorbar_ticks[n] + else formatter + ), + ) + elif k == 0 and cfg.colorbar_position[0] != -1: + cb[0] = fig.colorbar( + imag, + cax=fig.add_axes(cfg.colorbar_position), + ticks=vect, + label=ncolor, + format=( + mticker.FixedFormatter(cfg.colorbar_ticks[n]) + if cfg.colorbar_ticks[n] + else formatter + ), + shrink=0.2, + location="top", + ) + else: + if cfg.color_log_ticks: + + class LogTickFormatter(LogFormatter): + def set_locs(self, locs: Any | None = None) -> None: + """Set logarithmic colorbar sublabels from the configuration. + + Parameters + ---------- + locs : Any, optional + Tick locations supplied by Matplotlib. + + """ + self._sublabels = set(cfg.color_log_ticks) + + if cfg.subplot_grid[0]: + if cfg.colorbar_position[0] != -1: + if cfg.color_log_ticks: + cb[k] = fig.colorbar( + imag, + cax=fig.add_axes(cfg.colorbar_position), + label=ncolor, + shrink=0.2, + location="top", + ticks=cfg.color_log_ticks, + format=LogTickFormatter(), + ) + else: + cb[k] = fig.colorbar( + imag, + cax=fig.add_axes(cfg.colorbar_position), + label=ncolor, + shrink=0.2, + location="top", + ) + else: + if cfg.color_log_ticks: + cb[k] = fig.colorbar( + imag, + cax=divider.append_axes("right", size="5%", pad=0.05), + orientation="vertical", + label=ncolor, + ticks=cfg.color_log_ticks, + format=LogTickFormatter(), + ) + else: + cb[k] = fig.colorbar( + imag, + cax=divider.append_axes("right", size="5%", pad=0.05), + orientation="vertical", + label=ncolor, + ) + else: + _add_map_overlay(fig, cfg, imag, divider, vect, n, var, features, labels) + imag.set_clim( + minc - shc, + maxc + shc, + ) + _set_axis( + fig, + axes, + cfg, + data, + var, + n, + t, + k, + n_s, + unit, + xc, + yc, + extinf, + named, + deckd, + defcol, + slice_title, + feature_id, + ) + if cfg.xlabel[n] and cfg.hide_map_elements[1] == 0: + axis.set_xlabel(cfg.xlabel[n]) + elif ( + cfg.hide_map_elements[1] == 0 + and len(cfg.variables) == 1 + and (k + sub1 >= len(cfg.cases[0]) or not cfg.subplot_grid[0]) + ): + if len(data.steps) > 1 and cfg.subplot_grid[0] and len(cfg.cases[0]) == 1: + if k + sub1 >= len(data.steps): + axis.set_xlabel(f"{xname+cfg.xunit}") + else: + axis.set_xlabel(f"{xname+cfg.xunit}") + elif ( + cfg.hide_map_elements[1] == 0 + and len(cfg.cases[0]) == 1 + and (k + sub1 >= len(cfg.variables) or not cfg.subplot_grid[0]) + ) or ( + cfg.hide_map_elements[1] == 0 + and len(cfg.cases[0]) == len(cfg.variables) + and len(cfg.variables) > 1 + and (k + sub1 >= len(cfg.variables) or not cfg.subplot_grid[0]) + ): + axis.set_xlabel(f"{xname+cfg.xunit}") + if cfg.ylabel[n] and cfg.hide_map_elements[0] == 0: + axis.set_ylabel(cfg.ylabel[n]) + elif cfg.hide_map_elements[0] == 0 and (k % sub1 == 0 or not cfg.subplot_grid[0]): + axis.set_ylabel(f"{yname+cfg.yunit}") + if cfg.hide_map_elements[2] == 1 and len(fig.axes) > 1: + fig.delaxes(fig.axes[1]) + if ( + cfg.hide_map_elements[1] == 1 + or ( + k + sub1 < len(cfg.cases[0]) + and cfg.subplot_grid[0] + and len(cfg.variables) == 1 + and cfg.remove_duplicate_labels + ) + or cfg.hide_map_elements[1] == 1 + or ( + k + sub1 < len(cfg.variables) + and cfg.subplot_grid[0] + and len(cfg.cases[0]) == 1 + and cfg.remove_duplicate_labels + ) + or ( + k + sub1 < len(data.steps) + and len(data.steps) > 1 + and cfg.subplot_grid[0] + and len(cfg.cases[0]) == 1 + and cfg.remove_duplicate_labels + ) + ): + axis.tick_params(axis="x", which="both", bottom=False, labelbottom=False) + if cfg.hide_map_elements[0] == 1 or ( + k % sub1 > 0 and cfg.subplot_grid[0] and cfg.remove_duplicate_labels == 1 + ): + axis.tick_params(axis="y", which="both", left=False, labelleft=False) + axis.set_facecolor(cfg.fc) + if not cfg.gif: + if cfg.subplot_grid[0]: + if ( + t == len(data.steps) - 1 + and len(data.steps) > 1 + or n == len(cfg.variables) - 1 + and len(cfg.variables) > 1 + ): + _save_map( + fig, + cfg, + data, + generated_files, + named, + var, + slice_name, + t, + n, + ) + else: + if len(data.steps) == 1: + if k == max(len(cfg.variables) - 1, len(cfg.cases[0]) - 1): + _save_map( + fig, + cfg, + data, + generated_files, + named, + var, + slice_name, + t, + n, + ) + elif ( + len(cfg.cases[0]) == 1 + or len(data.steps) > 1 + and len(cfg.cases[0]) == len(data.steps) + ): + if t == len(data.steps) - 1: + _save_map( + fig, + cfg, + data, + generated_files, + named, + var, + slice_name, + t, + n, + ) + else: + _save_map( + fig, + cfg, + data, + generated_files, + named, + var, + slice_name, + t, + n, + ) + else: + save_index = t if cfg.rst_range else n + _save_map( + fig, + cfg, + data, + generated_files, + named, + var, + slice_name, + t, + save_index, + ) + plt.close() + + +def _clean_name(name: str) -> str: + """Convert a variable expression to a filename-safe stem. + + Parameters + ---------- + name : str + Variable expression or filename stem. + + Returns + ------- + str + Name with operators and spaces replaced. + + """ + name = name.replace(" / ", "_over_") + name = name.replace(" ", "") + return name + + +def _save_map( + fig: Figure, + cfg: PlopmConfig, + data: SimData, + generated_files: list[str], + named: str, + var: str, + slice_name: str, + t: int, + save_index: int, +) -> None: + """Save the current spatial map as a PNG file. + + Parameters + ---------- + fig : matplotlib.figure.Figure + Figure containing the map. + cfg : PlopmConfig + Output filename, directory, resolution, and face-color settings. + data : SimData + Simulation data containing the selected restart steps. + generated_files : list[str] + Generated filenames updated in place. + named : str + Case name used in the default filename. + var : str + Plotted variable name or expression. + slice_name : str + Slice description used in the default filename. + t : int + Index of the restart step being plotted. + save_index : int + Index used to select a custom filename. + + """ + fig.set_facecolor(cfg.fc) + name = _clean_name(f"{named}_{var}_{slice_name}_t{data.steps[t]}") + if save_index < len(cfg.filename) and cfg.filename[save_index]: + name = cfg.filename[save_index] + + filename = f"{name}.png" + fig.savefig( + f"{cfg.output_dir}/{filename}", + bbox_inches="tight", + dpi=int(cfg.dpi[0]), + ) + generated_files.append(filename) + + +def _remove_colorbar( + axes: Any, + original_loc: list[Any], + cb: list[Any], + colorbar_index: int, +) -> tuple[Any, list[Any]]: + """Remove a colorbar and restore its axes locator. + + Parameters + ---------- + axes : matplotlib.axes.Axes or np.ndarray + Map axes. + original_loc : list + Original axes locators. + cb : list + Active colorbar objects. + colorbar_index : int + Colorbar and axes index to restore. + + Returns + ------- + tuple + Updated axes and colorbar list. + + """ + if ( + colorbar_index < len(cb) + and colorbar_index < len(original_loc) + and cb[colorbar_index] != "" + ): + cb[colorbar_index].remove() + axes.flat[colorbar_index].set_axes_locator(original_loc[colorbar_index]) + cb[colorbar_index] = "" + return axes, cb + + +def _add_map_overlay( + fig: Figure, + cfg: PlopmConfig, + imag: ScalarMappable, + divider: AxesDivider, + vect: NDArray, + n: int, + var: str, + features: list | None, + labels: list[str], +) -> None: + """Add a categorical colorbar and labels for map features. + + Parameters + ---------- + fig : matplotlib.figure.Figure + Figure containing the map. + cfg : PlopmConfig + Initialized map configuration. + imag : matplotlib.cm.ScalarMappable + Mappable used to construct the colorbar. + divider : mpl_toolkits.axes_grid1.axes_divider.AxesDivider + Divider associated with the map axis. + vect : np.ndarray + Categorical colorbar tick values. + n : int + Variable index. + var : str + Categorical variable, such as ``"wells"`` or ``"faults"``. + features : list, optional + Feature locations grouped by label. + labels : list[str] + Feature names. + + """ + fig.colorbar( + imag, + cax=divider.append_axes("right", size="0%", pad=0.05), + orientation="vertical", + ticks=vect, + format=lambda x, _: "", + ) + feature_id = len(labels) + 1 + if var in ["faults", "wells"] and features is not None: + cmap = matplotlib.colormaps[cfg.colormaps[n]] + colour = cmap(np.linspace(0, 1, feature_id)) + if feature_id < 70: + for label_index, label_name in enumerate(labels): + _add_label(features, label_index, label_name, colour) + else: + for label_index, label_name in zip( + [0, len(getattr(cfg, var)) - 1], [labels[0], labels[-1]] + ): + _add_label(features, label_index, label_name, colour) + + +def _add_label( + features: list, + label_index: int, + label_name: str, + colour: NDArray, +) -> None: + """Draw one feature label when the feature is present. + + Parameters + ---------- + features : list + Feature locations grouped by label. + label_index : int + Index of the feature group. + label_name : str + Text shown beside the categorical colorbar. + colour : np.ndarray + Colors assigned to feature groups. + + """ + item = features[label_index] + if any(item): + plt.text( + 0, + label_index + 1, + f"{label_name}", + c=colour[label_index], + fontweight="bold", + ) +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/plopm/utils/write_vtk.html b/docs/_modules/plopm/utils/write_vtk.html new file mode 100644 index 0000000..52b2eb6 --- /dev/null +++ b/docs/_modules/plopm/utils/write_vtk.html @@ -0,0 +1,1028 @@ + + + + + + + + + + plopm.utils.write_vtk — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for plopm.utils.write_vtk

+# SPDX-FileCopyrightText: 2024-2026 NORCE Research AS
+# SPDX-License-Identifier: GPL-3.0
+# pylint: disable=W3301,R0912,R0913,R0914,R0915,R0917,E1102
+
+"""Create VTK files from OPM Flow simulation results.
+
+The module runs a minimal OPM Flow job when grid geometry is unavailable,
+populates VTU cell-data arrays for selected restart steps, and writes the PVD
+collection used to open the resulting time series.
+"""
+
+import os
+import shlex
+import shutil
+import sys
+from contextlib import nullcontext
+from subprocess import run
+
+import numpy as np
+from alive_progress import alive_bar
+from numpy.typing import NDArray
+
+from plopm.config.config import SimData
+from plopm.utils.readers import read_case, read_quantity
+from plopm.utils.terminal import cli_error_value, plopm_error, plopm_warning
+
+VTK_DTYPES = {
+    "Float64": np.float64,
+    "Float32": np.float32,
+    "Float16": np.float16,
+    "Int64": np.int64,
+    "UInt64": np.uint64,
+    "Int32": np.int32,
+    "UInt32": np.uint32,
+    "Int16": np.int16,
+    "UInt16": np.uint16,
+    "Int8": np.int8,
+    "UInt8": np.uint8,
+}
+
+
+
+[docs] +def make_vtks( + flow: str, + names: list, + output: str, + save: list, + restart: list, + variables: list, + vtkformat_list: list, + vtknames: list, + gif: bool, + vtk: bool, + filters: list, + scales: list[str], + mass: list[str], + mass_all: list[str], + caprock: list[str], + stress: float, + filterss: list[str], +) -> list: + """Create VTK time-series output for the configured cases. + + A minimal OPM Flow run creates the grid-only VTU file when needed. Selected + properties are then read from INIT or UNRST output and written to one VTU + file per restart step. + + Parameters + ---------- + flow : str + Command used to run OPM Flow. + names : list + Simulation-case stems grouped by the CLI input. + output : str + Directory in which VTK files are written. + save : list + Optional output stems for each case. + restart : list + Restart report steps to export. + variables : list + Variables or expressions written as cell data. + vtkformat_list : list + VTK data type selected for each variable. + vtknames : list + Optional VTK array names for each variable. + gif, vtk : bool + Output-mode flags passed to the simulation readers. + filters : list + Property filters used while loading each case. + scales : list[str] + Scale factor applied to each variable. + mass, mass_all : list[str] + Mass variables and all supported mass-related variables. + caprock : list[str] + Supported caprock-integrity variables. + stress : float + Vertical stress coefficient used for caprock quantities. + filterss : list[str] + Filter expressions applied while reading exported quantities. + + Returns + ------- + list[str] + Names of the generated PVD collection files. + + """ + generated_files: list[str] = [] + + for k, case in enumerate(names[0]): + deck = case + dname = case.split("/")[-1] + grid_name = f"{dname}-GRID.vtu" + grid_path = os.path.join(output, grid_name) + + if not os.path.isfile(f"{deck}.DATA"): + plopm_error(f"unable to find {cli_error_value(f'{deck}.DATA')}.") + + if not os.path.isfile(grid_path): + cwd = os.getcwd() + output_abs = os.path.abspath(output) + dryrun_deck = "" + dryrun_folder = "" + dryrun_parent = cwd + try: + if len(case.split("/")) > 1: + os.chdir("/".join(case.split("/")[:-1])) + dryrun_parent = os.getcwd() + flags, thermal = _vtk_flags() + flow_command = shlex.split(flow) + dryrun_deck = f"{dname}_DRYRUN_{os.getpid()}.DATA" + dryrun_folder = f"plopm_{os.getpid()}" + shutil.copyfile(f"{dname}.DATA", dryrun_deck) + flags += " --enable-dry-run=1" + os.makedirs(dryrun_folder, exist_ok=True) + deck_rel = f"../{dryrun_deck}" + os.chdir(dryrun_folder) + if "SPE11B" in dname or "SPE11C" in dname: + run( + flow_command + + [deck_rel] + + shlex.split(flags) + + shlex.split(thermal), + check=False, + ) + else: + run(flow_command + [deck_rel] + shlex.split(flags), check=False) + shutil.move( + f"{dname}_DRYRUN_{os.getpid()}-00000.vtu", + os.path.join(output_abs, grid_name), + ) + finally: + os.chdir(dryrun_parent) + if dryrun_folder: + shutil.rmtree(dryrun_folder, ignore_errors=True) + if dryrun_deck and os.path.isfile(dryrun_deck): + os.remove(dryrun_deck) + os.chdir(cwd) + + generated_files.append(grid_name) + + data = read_case(case, gif, vtk, variables, restart, filters) + _write_vtk_data( + case, + data, + output, + dname, + save, + variables, + vtkformat_list, + vtknames, + k, + scales, + mass, + mass_all, + caprock, + stress, + filterss[k], + ) + + where = save[k] if save[k] else dname + generated_files.extend( + f"{where}-{int(restart_index):04d}.vtu" for restart_index in data.steps + ) + + _write_pvd( + save, + dname, + data.steps, + data.times, + output, + k, + ) + generated_files.append(f"{where}.pvd") + + return list(dict.fromkeys(generated_files))
+ + + +def _write_pvd( + save: list, dname: str, restart: list, tnrst: list, output: str, k: int +) -> None: + """Write a PVD collection for a VTU time series. + + Parameters + ---------- + save : list + Optional output stems for each case. + dname : str + Default case name. + restart : list + Restart report steps included in the collection. + tnrst : list + Simulation times indexed by restart report step. + output : str + Output directory. + k : int + Case index used to select the output stem. + + """ + where = save[k] if save[k] else dname + pvd_lines = [] + pvd_lines.append( + "<?xml version='1.0'?>\n" + + "<VTKFile type='Collection'\n" + + " version='0.1'\n" + + " byte_order='LittleEndian'\n" + + " compressor='vtkZLibDataCompressor'>\n" + + " <Collection>\n" + ) + for i in restart: + pvd_lines.append( + f" <DataSet timestep='{tnrst[i]}' file='{where}-{int(i):04d}.vtu'/>\n" + ) + pvd_lines.append(" </Collection>\n</VTKFile>") + with open( + f"{output}/{where}.pvd", + "w", + encoding="utf8", + ) as file: + file.write("".join(pvd_lines)) + + +def _warn_once(warning_keys: set, warning_key, message: str) -> None: + """Emit a warning once for a unique key. + + Parameters + ---------- + warning_keys : set + Keys for warnings already emitted. + warning_key + Hashable key identifying the warning condition. + message : str + Warning message. + + """ + if warning_key not in warning_keys: + plopm_warning(message) + warning_keys.add(warning_key) + + +def _check_integer_conversion( + values: NDArray, + var: str, + vtkformat: str, + target_dtype: type, + warning_keys: set[tuple[str, str, str]], +) -> None: + """Warn about unsafe conversion to an integer VTK type. + + Warnings cover non-numeric or non-finite values, negative values converted + to unsigned integers, decimal truncation, and values outside the target + integer range. + + Parameters + ---------- + values : np.ndarray + Quantity values to inspect. + var : str + Variable name used in warning messages. + vtkformat : str + Requested VTK data type. + target_dtype : type + NumPy dtype used for conversion. + warning_keys : set[tuple[str, str, str]] + Keys for warnings already emitted. + + """ + try: + numeric_values = np.asarray(values, dtype=np.float64) + except TypeError: + _warn_once( + warning_keys, + (var.upper(), vtkformat, "non_numeric"), + f"{var.upper()} contains non-numeric values but is written as {vtkformat}.", + ) + return + if not numeric_values.size: + return + finite_mask = np.isfinite(numeric_values) + finite_values = numeric_values[finite_mask] + if finite_values.size != numeric_values.size: + _warn_once( + warning_keys, + (var.upper(), vtkformat, "non_finite"), + f"{var.upper()} contains non-finite values but is written as {vtkformat}.", + ) + if not finite_values.size: + return + dtype_info = np.iinfo(target_dtype) + min_val = finite_values.min() + max_val = finite_values.max() + if np.issubdtype(target_dtype, np.unsignedinteger) and min_val < 0: + _warn_once( + warning_keys, + (var.upper(), vtkformat, "negative_unsigned"), + f"{var.upper()} contains negative values but is written as {vtkformat}; " + "NumPy may wrap them.", + ) + if np.any(finite_values != np.trunc(finite_values)): + _warn_once( + warning_keys, + (var.upper(), vtkformat, "float_truncation"), + f"{var.upper()} contains float values but is written as {vtkformat}; " + "NumPy will truncate decimals.", + ) + if min_val < dtype_info.min or max_val > dtype_info.max: + _warn_once( + warning_keys, + (var.upper(), vtkformat, "out_of_range"), + f"{var.upper()} contains values outside {vtkformat} range [{dtype_info.min}, " + f"{dtype_info.max}]; NumPy may wrap or fail depending on version.", + ) + + +def _format_vtk_array(values: NDArray, target_dtype: type) -> str: + """Format values for an ASCII VTK DataArray. + + Parameters + ---------- + values : np.ndarray + Values to flatten and convert. + target_dtype : type + NumPy dtype used for the output values. + + Returns + ------- + str + Tab-indented values ready for insertion into a VTU file. + + """ + values = np.ravel(np.asarray(values, dtype=target_dtype)) + if np.issubdtype(np.dtype(target_dtype), np.floating): + values = np.char.mod("%.8f", values) + values = np.char.rstrip(np.char.rstrip(values, "0"), ".") + values = np.where(values == "-0", "0", values) + else: + values = values.astype(str) + return "\t\t\t\t\t " + " ".join(values) + "\n\t\t\t\t\t</DataArray>" + + +def _write_vtk_data( + case: str, + data: SimData, + output: str, + dname: str, + save: list, + variables: list, + vtkformat_list: list, + vtknames: list, + k: int, + scales: list[str], + mass: list[str], + mass_all: list[str], + caprock: list[str], + stress: float, + filterss: str, +) -> None: + """Populate grid VTU files with simulation cell data. + + Parameters + ---------- + case : str + Simulation-case stem. + data : SimData + Loaded OPM simulation data. + output : str + Output directory. + dname : str + Default case name. + save : list + Optional output stems for each case. + variables : list + Variables or expressions written as cell data. + vtkformat_list : list + VTK data type selected for each variable. + vtknames : list + Optional VTK array names. + k : int + Case index used to select output settings. + scales : list[str] + Scale factor applied to each variable. + mass, mass_all : list[str] + Mass variables and all supported mass-related variables. + caprock : list[str] + Supported caprock-integrity variables. + stress : float + Vertical stress coefficient used for caprock quantities. + filterss : str + Filter expression applied while reading quantities. + + """ + restart = data.steps + vtk_lines = [] + skip = False + warning_keys: set[tuple[str, str, str]] = set() + with open(f"{output}/{dname}-GRID.vtu", encoding="utf8") as file: + for line in file: + if skip and "CellData" in line: + skip = False + continue + if "CellData" in line: + skip = True + if not skip: + vtk_lines.append(line) + where = save[k] if save[k] else dname + show_progress = sys.stdout.isatty() + if show_progress: + bar_ctx = alive_bar(len(restart) * len(variables), bar="fish") + else: + bar_ctx = nullcontext() + with bar_ctx as bar_animation: + for i in restart: + cell_data = [ + "\t\t\t\t<CellData Scalars='File created by https://github.com/cssr-tools/plopm'>", + ] + for n, var in enumerate(variables): + if show_progress: + bar_animation() + unit, values = read_quantity( + case, + data, + var, + i, + float(scales[n]), + mass, + mass_all, + caprock, + stress, + filterss, + False, + "", + "", + [False], + ) + + vtkformat = vtkformat_list[n] + target_dtype = VTK_DTYPES[vtkformat] + if np.issubdtype(target_dtype, np.integer): + _check_integer_conversion( + values, var, vtkformat, target_dtype, warning_keys + ) + # VTK XML interoperability for Float16 is limited in many readers, + # so we emit Float32 in the DataArray type while preserving values. + if vtkformat == "Float16": + vtkformat = "Float32" + cell_data.append( + f"\n\t\t\t\t\t<DataArray type='{vtkformat}' Name=" + + f"'{vtknames[n] if vtknames[n] else var+unit}' " + + "NumberOfComponents='1' format='ascii'>\n" + ) + cell_data.append(_format_vtk_array(values, target_dtype)) + cell_data.append("\n\t\t\t\t</CellData>\n") + with open( + f"{output}/{where}-{int(i):04d}.vtu", + "w", + encoding="utf8", + ) as file: + file.write("".join(vtk_lines[:4] + cell_data + vtk_lines[4:])) + + +def _vtk_flags() -> tuple[str, str]: + """Build OPM Flow options for a minimal VTK run. + + Returns + ------- + tuple[str, str] + General VTK options and optional thermal-model options. + + """ + flags = ( + " --enable-vtk-output=1 --enable-ecl-output=0 --output-mode=none" + + " --vtk-write-temperature=0 --vtk-write-densities=0 --vtk-write-mole-fractions=0 " + + "--vtk-write-relative-permeabilities=0 --vtk-write-pressures=0 " + + "--vtk-write-saturations=0 --vtk-write-porosity=0" + ) + thermal = "" + return flags, thermal +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_sources/about.rst.txt b/docs/_sources/about.rst.txt deleted file mode 100644 index 1d602a4..0000000 --- a/docs/_sources/about.rst.txt +++ /dev/null @@ -1,9 +0,0 @@ -=========== -About plopm -=========== - -.. image:: ./figs/about.png - -**plopm** is being funded by the `HPC Simulation Software for the Gigatonne Storage Challenge project `_ -[project number 622059] and `Center for Sustainable Subsurface Resources (CSSR) `_ [project no. 331841]. -Contributions are more than welcome using the fork and pull request approach. For new features, please request them raising an issue. diff --git a/docs/_sources/api.rst.txt b/docs/_sources/api.rst.txt index 6d8dfa8..45c6da3 100644 --- a/docs/_sources/api.rst.txt +++ b/docs/_sources/api.rst.txt @@ -1,10 +1,16 @@ -================ -plopm Python API -================ +.. _api-reference: -The main script for the **plopm** executable is located in the `core `_ folder. -The `config `_ folder contains the two dataclass used. -The `utils `_ folder contains all different methods to handle the plotting. +Python API +========== +The Python API documents the public modules and functions provided by +**plopm**. For command syntax and options, see the +:doc:`Command-line reference `. -.. include:: modules.rst +API documentation +----------------- + +.. toctree:: + :maxdepth: 2 + + api/modules diff --git a/docs/_sources/modules.rst.txt b/docs/_sources/api/modules.rst.txt similarity index 100% rename from docs/_sources/modules.rst.txt rename to docs/_sources/api/modules.rst.txt diff --git a/docs/_sources/plopm.config.config.rst.txt b/docs/_sources/api/plopm.config.config.rst.txt similarity index 87% rename from docs/_sources/plopm.config.config.rst.txt rename to docs/_sources/api/plopm.config.config.rst.txt index 8697e9c..9cd9ede 100644 --- a/docs/_sources/plopm.config.config.rst.txt +++ b/docs/_sources/api/plopm.config.config.rst.txt @@ -3,6 +3,5 @@ plopm.config.config module .. automodule:: plopm.config.config :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.config.rst.txt b/docs/_sources/api/plopm.config.rst.txt similarity index 91% rename from docs/_sources/plopm.config.rst.txt rename to docs/_sources/api/plopm.config.rst.txt index 59596e6..8dd86fd 100644 --- a/docs/_sources/plopm.config.rst.txt +++ b/docs/_sources/api/plopm.config.rst.txt @@ -14,6 +14,5 @@ Module contents .. automodule:: plopm.config :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.core.plopm.rst.txt b/docs/_sources/api/plopm.core.plopm.rst.txt similarity index 86% rename from docs/_sources/plopm.core.plopm.rst.txt rename to docs/_sources/api/plopm.core.plopm.rst.txt index 074cd2c..c4b7cb6 100644 --- a/docs/_sources/plopm.core.plopm.rst.txt +++ b/docs/_sources/api/plopm.core.plopm.rst.txt @@ -3,6 +3,5 @@ plopm.core.plopm module .. automodule:: plopm.core.plopm :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.core.rst.txt b/docs/_sources/api/plopm.core.rst.txt similarity index 91% rename from docs/_sources/plopm.core.rst.txt rename to docs/_sources/api/plopm.core.rst.txt index 29e5cb7..547be33 100644 --- a/docs/_sources/plopm.core.rst.txt +++ b/docs/_sources/api/plopm.core.rst.txt @@ -14,6 +14,5 @@ Module contents .. automodule:: plopm.core :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.rst.txt b/docs/_sources/api/plopm.rst.txt similarity index 91% rename from docs/_sources/plopm.rst.txt rename to docs/_sources/api/plopm.rst.txt index 88d4f79..29faaa9 100644 --- a/docs/_sources/plopm.rst.txt +++ b/docs/_sources/api/plopm.rst.txt @@ -16,6 +16,5 @@ Module contents .. automodule:: plopm :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.initialization.rst.txt b/docs/_sources/api/plopm.utils.initialization.rst.txt similarity index 88% rename from docs/_sources/plopm.utils.initialization.rst.txt rename to docs/_sources/api/plopm.utils.initialization.rst.txt index 41c471a..042fc36 100644 --- a/docs/_sources/plopm.utils.initialization.rst.txt +++ b/docs/_sources/api/plopm.utils.initialization.rst.txt @@ -3,6 +3,5 @@ plopm.utils.initialization module .. automodule:: plopm.utils.initialization :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.mapping.rst.txt b/docs/_sources/api/plopm.utils.mapping.rst.txt similarity index 87% rename from docs/_sources/plopm.utils.mapping.rst.txt rename to docs/_sources/api/plopm.utils.mapping.rst.txt index fbc649e..82176dc 100644 --- a/docs/_sources/plopm.utils.mapping.rst.txt +++ b/docs/_sources/api/plopm.utils.mapping.rst.txt @@ -3,6 +3,5 @@ plopm.utils.mapping module .. automodule:: plopm.utils.mapping :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.readers.rst.txt b/docs/_sources/api/plopm.utils.readers.rst.txt similarity index 87% rename from docs/_sources/plopm.utils.readers.rst.txt rename to docs/_sources/api/plopm.utils.readers.rst.txt index 6e04091..5fd2656 100644 --- a/docs/_sources/plopm.utils.readers.rst.txt +++ b/docs/_sources/api/plopm.utils.readers.rst.txt @@ -3,6 +3,5 @@ plopm.utils.readers module .. automodule:: plopm.utils.readers :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.rst.txt b/docs/_sources/api/plopm.utils.rst.txt similarity index 94% rename from docs/_sources/plopm.utils.rst.txt rename to docs/_sources/api/plopm.utils.rst.txt index 6aaf0a2..a550656 100644 --- a/docs/_sources/plopm.utils.rst.txt +++ b/docs/_sources/api/plopm.utils.rst.txt @@ -20,6 +20,5 @@ Module contents .. automodule:: plopm.utils :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.terminal.rst.txt b/docs/_sources/api/plopm.utils.terminal.rst.txt similarity index 87% rename from docs/_sources/plopm.utils.terminal.rst.txt rename to docs/_sources/api/plopm.utils.terminal.rst.txt index 43e32e9..89d2575 100644 --- a/docs/_sources/plopm.utils.terminal.rst.txt +++ b/docs/_sources/api/plopm.utils.terminal.rst.txt @@ -3,6 +3,5 @@ plopm.utils.terminal module .. automodule:: plopm.utils.terminal :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.write_oned.rst.txt b/docs/_sources/api/plopm.utils.write_oned.rst.txt similarity index 88% rename from docs/_sources/plopm.utils.write_oned.rst.txt rename to docs/_sources/api/plopm.utils.write_oned.rst.txt index 2afa215..e23771d 100644 --- a/docs/_sources/plopm.utils.write_oned.rst.txt +++ b/docs/_sources/api/plopm.utils.write_oned.rst.txt @@ -3,6 +3,5 @@ plopm.utils.write\_oned module .. automodule:: plopm.utils.write_oned :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.write_twod.rst.txt b/docs/_sources/api/plopm.utils.write_twod.rst.txt similarity index 88% rename from docs/_sources/plopm.utils.write_twod.rst.txt rename to docs/_sources/api/plopm.utils.write_twod.rst.txt index 1364d69..19f53ee 100644 --- a/docs/_sources/plopm.utils.write_twod.rst.txt +++ b/docs/_sources/api/plopm.utils.write_twod.rst.txt @@ -3,6 +3,5 @@ plopm.utils.write\_twod module .. automodule:: plopm.utils.write_twod :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/plopm.utils.write_vtk.rst.txt b/docs/_sources/api/plopm.utils.write_vtk.rst.txt similarity index 87% rename from docs/_sources/plopm.utils.write_vtk.rst.txt rename to docs/_sources/api/plopm.utils.write_vtk.rst.txt index a698b13..78e0b42 100644 --- a/docs/_sources/plopm.utils.write_vtk.rst.txt +++ b/docs/_sources/api/plopm.utils.write_vtk.rst.txt @@ -3,6 +3,5 @@ plopm.utils.write\_vtk module .. automodule:: plopm.utils.write_vtk :members: - :private-members: :show-inheritance: :undoc-members: diff --git a/docs/_sources/command-line.rst.txt b/docs/_sources/command-line.rst.txt new file mode 100644 index 0000000..3edfb54 --- /dev/null +++ b/docs/_sources/command-line.rst.txt @@ -0,0 +1,29 @@ +.. _command-line-reference: + +Command-line reference +====================== + +This section describes the **plopm** command syntax and all supported +command-line options. + +Start with :doc:`options/syntax` for input lists, variables, model slices, +restart steps, text separators, and output formats. For guided workflows, see +the :doc:`tutorial`. For task-oriented commands, browse the :doc:`examples`. + +.. toctree:: + :maxdepth: 1 + + options/syntax + options/input-data + options/output + options/selection + options/filtering + options/computation + options/plot-types + options/layout + options/titles-labels + options/axes + options/styling + options/vtk + options/gif + options/diagnostics diff --git a/docs/_sources/examples.rst.txt b/docs/_sources/examples.rst.txt index b9785de..9032af6 100644 --- a/docs/_sources/examples.rst.txt +++ b/docs/_sources/examples.rst.txt @@ -1,564 +1,172 @@ -******** +.. _examples-gallery: + Examples -******** +======== + +Select an example to view its commands, figures, and related options. See `this presentation `_ from the OPM summit 2025 for additional examples using **plopm**, as well as the one from `the OPM summit 2026 `_. .. warning:: - By default the figure is generated from the front cells on the xy-plane (-s ,1,) and the axes are scaled (-asp 1), which for models with large lateral - extend could lead to a figure such as the below one: - - .. figure:: figs/docs_z_flag.png - - Then, you could set these flags to **-s ,,1 -asp 0** when you run **plopm** to not scale the axes and to plot the top view of the model. - -.. tip:: - You can try to generate all figures from the examples below by executing inside the plopm folder: - - .. code-block:: bash - - . tests/scripts/docs_all.sh - - See the files inside the scripts folder for the commands to be run. - - -=========== -Hello world -=========== - -The simulation files located in the `examples folder `_ were generated using -`pyopmspe11 `_ by running this `configuration file `_. -Then, if you succeed in installing **plopm**, inside the `examples folder `_ by typing in the terminal - -.. code-block:: bash - - plopm -i SPE11B - -the following figure should be generated (this example is used in the `tests `_, then it runs with the default terminal argument options). - -.. figure:: figs/spe11b_satnum_*,1,*_t5.png - -See the :ref:`overview` or run `plopm -h` for the definition of the argument options, as well as using `-lv 1` flag to output the available -summary, init, and restart available variables given an input deck. - -For example, for the gas saturation at the report step number 4 with three colorbar labels using a given colormap (-c) and defined colorbar ticks (-cbt): - -.. code-block:: bash - - plopm -i SPE11B -v sgas -r 4 -cbn 3 -c cubehelix -cbt '[0, middle, 0.9]' - -.. figure:: figs/spe11b_sgas_i,1,k_t4.png - -and for the gas in place summary vector given a color, line style, font size, dimension of the figure, line width, and using dates for the times: - -.. code-block:: bash - - plopm -i SPE11B -v fgip -c b -ls dotted -fz 12 -fs 5,5 -lw 4 -tu dates - -.. figure:: figs/fgip.png - :scale: 7% - -To plot cell values over time, this can be achieved by: - -.. code-block:: bash - - plopm -i 'SPE11B SPE11B SPE11B' -v 'pressure - 0pressure' -s '1,1,1 41,1,29 83,1,58' -llb 'Top left corner Middle Right lower corner' -yl 'Pressure increase at the sensor locations [bar]' -yf .0f -xnt 11 -tu dates - -.. figure:: figs/spe11b_pressure-0pressure.png - :scale: 20% - -.. tip:: - - All previous commands can be executed as (`docs_hello_world.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_hello_world.sh - -========= -Colormaps -========= - -The flag **-c** allows to set `colormaps from Matplotlib `_ (e.g., **-c turbo**), -`colormaps from colorcet `_ (e.g., **-c cet_glasbey_bw**), or user defined colorbars, where -each color is given in RGB (e.g., **-c '193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130'**) or HEX format (e.g., **-c '#b6c406 #fffa86'**). - -Different colormap formats can be used when making a subfigure, for example: - -.. code-block:: bash - - plopm -i SPE11B -v satnum,fipnum,disperc -c '193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130',cet_glasbey_bw,'#b6c406 #fffa86' -sg 3,1 -rdl 1 -cbn 3,6,2 -cbf .0f,.0f,.1f -fs 7,4 - -.. figure:: figs/spe11b_disperc_i,1,k_t5.png - :scale: 20% - -.. tip:: - - All previous commands can be executed as (`docs_colormaps.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_colormaps.sh - -============ -Generic deck -============ - -See/run the `test_generic_deck.py `_ -for an example where **plopm** is used to generate figures from the -`SPE10_MODEL2 model `_ by downloading the files and using the -`OPM Flow `_ simulator. - -.. image:: ./figs/spe10_model2_permz_*,4,*_t0.png - -.. code-block:: bash - - plopm -i SPE10_MODEL2 -v permz -s ,4, -clog 1 -xu km -yu km -xnt 6 -yf .2f -t 'K$_z$ at the forth slide in the xz plane' -cl '[1e-7,1e3]' -Here, we look at the forth slide in the xz plane and use log scale for the permeability in the z direction, as well as changing the axis units to km, -setting the format to the numbers to two floats in the y axis, and setting manually the upper and lower bound for the color map. - -To plot information for the grid, and also the location of the wells from the top view, this is achieved by: - -.. code-block:: bash - - plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v grid -hide 0,0,1,0 && plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v wells -hide 0,0,0,1 - -.. image:: ./figs/wells.png - -Here, we use the remove flag to delete the colorbar axis in the maps for the grid and to delete the generated title in the wells plot (the first entry -in remove would delete the left axis, e.g., the y label and y ticks in this example, while the second entry if set to 1 would remove the x axis). - -.. tip:: - - All previous commands can be executed as (`docs_generic_deck.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_generic_deck.sh - -=============================== -Rotation, translation, and zoom -=============================== - -This example relies on the simulation results in `opm-tests `_. If you -download the files in that folder, then by using the **plopm** tool: - -.. code-block:: bash - - plopm -i NORNE_ATW2013 -s ,,1 - -these are some of the generated figures: - -.. image:: ./figs/norne.png - -In order to reduce the white space outside the active cells, as well as to rotate the grid and translate it, this can be ahieved by: - -.. code-block:: bash - - plopm -i NORNE_ATW2013 -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -fz 8 - -.. image:: ./figs/norne_transformed.png - -To show all faults in the model and to only show the ones connected all along the z direction, this can be achieved by: - -.. code-block:: bash - - plopm -i NORNE_ATW2013 -v faults -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 - plopm -i NORNE_ATW2013 -v faults -s ,,1:22 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -agg max - -.. image:: ./figs/norne_faults.png - -To show all wells in the model and to only show the ones with at least one perforation on the top layer, this can be achieved by: - -.. code-block:: bash - - plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 -fn "norne_wells_global" - plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -fn "norne_wells" - -.. image:: ./figs/norne_wells.png + The default view is ``-s ,1,`` with equal axis scaling ``-asp 1``. For models with a + large lateral extent, use ``-s ,,1 -asp 0`` for an unscaled top view. .. note:: - For plotting the faults and wells, they must be specified in the input deck (no via include files). - -.. tip:: - - All previous commands can be executed as (`docs_rotation_translation_zoom.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_rotation_translation_zoom.sh - -========================== -Projections and subfigures -========================== - -Here is an example of making a single figure plotting subfigures and using different approaches to project the quantities: - -.. code-block:: bash - - plopm -i NORNE_ATW2013 -v 'index_k,permx,poro' -s ',,1:22 ,,1:22 ,,1:22' -agg 'first,arithmetic,max' -sg 1,3 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 24,10 -c 'PuOr,vanimo,jet' -cbf '.0f,.0f,.2f' -cbn '2,4,8' -st 0 -t "Top k values using first Averaged permx using arithmetic Values of porosity using max" -fz 18 - -.. image:: ./figs/norne_atw2013_poro_i,j,1:22_t64.png + OPM Flow is required to reproduce the examples with the supplied shell + scripts. Install it before running them; see + :ref:`opm-flow-installation`. .. tip:: - All previous commands can be executed as (`docs_projections_subfigures.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_projections_subfigures.sh - -========== -Histograms -========== - -Here is an example of two subfigures showing the histogram of the porosity and permeability in norne using 20 bins and norm and lognorm distributions -respectively, showing also the mean and std which can be used for sampling (see the test for additional examples): - -.. code-block:: bash + Generate all documented figures from the repository root: - plopm -i NORNE_ATW2013 -v poro,permx -hist '20,norm 20,lognorm' -ag 0 -sg 1,2 -fs 15,5 -ll 'upper center' -y '[0,10000] [0,23000]' -c '#7274b3,#cddb6e' + .. code-block:: console -.. image:: ./figs/norne_atw2013_permx.png + . tests/scripts/docs_all.sh -.. tip:: - - All previous commands can be executed as (`docs_histograms.sh `_): - - .. code-block:: bash + .. grid:: 1 2 2 2 + :gutter: 2 - . ./tests/scripts/docs_histograms.sh + .. grid-item:: -================= -Caprock integrity -================= + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_all.sh + :color: primary + :outline: + :expand: -Since there is an increase of interest in regional models, then we add three new variables **-v** related to the caprock integrity, -i.e., the most top active cells in the given range **-s**: + View script -#. limipres = stress*z-p0, where stress can be set via the flag **-sc** (0.134 by default, a common value in literature). -#. overpres = p-stress*z, i.e., a negative value means the limit pressure has not been reached. -#. objepres is the ratio of overpres to limipres, i.e., the value is of order of one and this can be used in optimization routines. + .. grid-item:: -Motivated for objepres, then now we add an option for mode to write a csv with the non nan values, i.e., **-m csv**. -For example, if we would like to estimate these values for norne for future CCS: + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_all.sh + :color: secondary + :outline: + :expand: -.. code-block:: bash + View raw script - plopm -i 'NORNE_ATW2013' -s ',,1:22 ,,1:22' -v limipres,overpres -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 15,10 -c Spectral,spring -sg 1,2 -rdl 1 - plopm -i 'NORNE_ATW2013' -m csv -v objepres -s ',,1:22' +Example gallery +--------------- -.. image:: ./figs/norne_atw2013_overpres_i,j,1:22_t64.png +.. grid:: 1 1 2 2 + :gutter: 3 -.. tip:: - - All previous commands can be executed as (`docs_caprock_integrity.sh `_): + .. grid-item-card:: Hello world + :link: example-hello-world + :link-type: ref + :img-top: figs/spe11b_sgas_i,1,k_t4.png - .. code-block:: bash + Create maps, summary plots, and cell time series. - . ./tests/scripts/docs_caprock_integrity.sh + .. grid-item-card:: Colormaps + :link: example-colormaps + :link-type: ref + :img-top: figs/spe11b_disperc_i,1,k_t5.png -====================== -Reading from csv files -====================== + Use named, RGB, and HEX colormaps. -Using the flag **-cc** allows to read values from csv files, allowing also to combine values from OPM Flow output files. To ilustrate this, -let us consider the `pyopmspe11 tool `_. + .. grid-item-card:: Generic deck + :link: example-generic-deck + :link-type: ref + :img-top: figs/spe10_model2_permz_*,4,*_t0.png -.. tip:: - You can install `pyopmspe11 tool `_ by executing in the terminal: pip install git+https://github.com/OPM/pyopmspe11.git. - Read the documentation in there to get familiar with the benchmark and the format of the csv files. + Plot a generic OPM Flow model. -Then, let us consider the configuration file `r1_Cart_10m.toml `_ from the benchmark folder. In line 2 of -that file set the number of cpus for the run (in the original file is 32; if you do not have mpi support, simply remove mpi, i.e., mpirun -np 32). To lower the simulation time, -in line 10 set x_n to 420 and line 12 set z_n to 60. In addition, in line 51 remove the 1000 years of initialization, i.e., the injection should be: + .. grid-item-card:: Rotation, translation, and zoom + :link: example-transformations + :link-type: ref + :img-top: figs/norne_transformed.png -.. code-block:: toml + Transform, crop, and inspect Norne. - inj = [[ 25, 5, 1, 0.035, 10, 1, 0, 10], - [ 25, 5, 1, 0.035, 10, 1, 0.035, 10], - [ 950, 5, 1, 0, 10, 1, 0, 10]] + .. grid-item-card:: Projections and subfigures + :link: example-projections + :link-type: ref + :img-top: figs/norne_atw2013_poro_i,j,1:22_t64.png -Once you have installed **pyopmspe11**, then run the configuration file: + Combine projection methods in one figure. -.. code-block:: bash + .. grid-item-card:: Histograms + :link: example-histograms + :link-type: ref + :img-top: figs/norne_atw2013_permx.png - pyopmspe11 -i r1_Cart_10m.toml -o r1_Cart_10m -m deck_flow_data -g all -t 5 -r 70,1,30 -w 0.1 -fz 0 + Plot property distributions. -This generates the output folder r1_Cart_10m, where the OPM Flow output files and the csvs are generated. To compare the spatial maps of the CO2 mass -fraction from the simulation grid to the reporting grid (70 by 30), this can be achieved by: + .. grid-item-card:: Caprock integrity + :link: example-caprock + :link-type: ref + :img-top: figs/norne_atw2013_overpres_i,j,1:22_t64.png -.. code-block:: bash + Evaluate pressure limits. - plopm -v xco2l -i "r1_Cart_10m/R1_CART_10M r1_Cart_10m/spe11b_spatial_map_500y" -cc ";1,2,5" -sg 2,1 -rdl 1 -r 100 -fs 10,3 -st 0 -t "Simulation grid Reporting grid" -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f + .. grid-item-card:: Reading CSV files + :link: example-csv + :link-type: ref + :img-top: figs/spe11b_spatial_map_500y_xco2l_csv_t100.png -where the flag **-cc ";1,2,5"** has two main entries (number of input files) separated by **;**, and the first entry is defaulted since the input it is -an OPM Flow file, while the second entry has three values, where the first two sets the columns in the csv where the x and y coordinates are, and the last entry (5) -it is the column for the plotted variable. The previous command generates the following figure: + Combine CSV and OPM Flow data. -.. image:: ./figs/spe11b_spatial_map_500y_xco2l_csv_t100.png + .. grid-item-card:: Convert to VTK + :link: example-vtk + :link-type: ref + :img-top: figs/vtk_temp.png -To compare two summary quantities, this can be achiaved by: + Export data for ParaView. -.. code-block:: bash + .. grid-item-card:: Relative permeability and capillary pressure + :link: example-relative-permeability + :link-type: ref + :img-top: figs/saturation_functions.png - plopm -i "r1_Cart_10m/spe11b_time_series r1_Cart_10m/R1_CART_10M" -v ",BWPR:256,1,5" -cc "1,3;" -sf "1e-5,1" -ls "solid,dotted" -lw "4,4" -yl "Sensor pressure [bar]" -llb "From csv file From OPM Flow output file" -c "r,k" + Plot saturation functions. -where for summary variables, the flag **-v ",BWPR:256,1,5"** needs to have empty entries for corresponding csv **-i** files, and the flag **-sf "1e-5,1"** allows to convert the values in Pascal to bar from the csv file, multiplying by 1e-5. The previous command generates the following figure: + .. grid-item-card:: Different inputs and ensembles + :link: example-ensembles + :link-type: ref + :img-top: figs/ensemble.png -.. image:: ./figs/spe11b_time_series_BWPR-1944.png + Compare cases and ensembles. -If you download the benchmark data from `this website `_, then you could use **plopm** to compare simulation results. -For example, by downloading the `spe11_opm1.zip `_, `spe11_opm2.zip `_, -`spe11_opm3.zip `_, and `spe11_opm4.zip `_, then you could compare -your simulations with those results by (to remove the legend, add the flag **-ll empty**): + .. grid-item-card:: Filters + :link: example-filters + :link-type: ref + :img-top: figs/filter_opm.png -.. code-block:: bash + Select cells with conditions. - plopm -i "opm1/spe11b_time_series opm2/spe11b_time_series opm3/spe11b_time_series opm4/spe11b_time_series r1_Cart_10m/spe11b_time_series" -cc "1,4;1,4;1,4;1,4;1,4" -tu y -x "[0,1000]" -yl "dissA [kiloton]" -yf .1f -sf 1e-6 -c "#a8d8e3,#a8d8e3,#a8d8e3,#a8d8e3,#fc035a" -lw 5,5,5,5,5 -ls solid + .. grid-item-card:: GIFs and masks + :link: example-animations + :link-type: ref + :img-top: figs/xco2l.gif -.. image:: ./figs/spe11b_time_series_csv_ens.png + Animate results and apply masks. -and for the spatial maps: - -.. code-block:: bash - - plopm -i "opm1/spe11b_spatial_map_250y opm2/spe11b_spatial_map_250y opm3/spe11b_spatial_map_250y opm4/spe11b_spatial_map_250y r1_Cart_10m/spe11b_spatial_map_250y" -cc "1,2,5;1,2,5;1,2,5;1,2,5;1,2,5" -sg 3,2 -rdl 1 -st 0 -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f -fs 14,4 -t "opm1 opm2 opm3 opm4 my simulation" -cbl 'Time 250 years, CO$_2$ mass fraction (liquid phase) [-]' -c inferno - -.. image:: ./figs/spe11b_spatial_map_250y_csv_csv_t-1.png - -To make a GIF from csvs, then write "PLOPM" in the csv file name (e.g., '-i opm1/spe11b_spatial_map_PLOPMy') where to read the given times from **-r** (see `these examples from pyopmspe11 `_). - -.. tip:: - In general, the ability of plotting from csv files using the flag **-cc** is a game changer, expanding the applicability of **plopm** beyond the format of OPM Flow output files. - -.. tip:: - - All previous commands can be executed as (`docs_reading_csvs.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_reading_csvs.sh - -============== -Convert to VTK -============== -Inside the `examples folder `_, then we can create VTKs from the -OPM Flow simulation results (i.e., .EGRID, .INIT, .UNRST). For example, to create VTKS for the temperature, fipnum, the co2 mass, and the co2 mass fraction in the liquid phase -from the restart files from the initial (0) to the number 5 restart, using a OPM Flow build from source in a given path, this can be achieved by: - -.. code-block:: bash - - plopm -i SPE11B -v temp,fipnum,co2m,xco2l -vf Float32,UInt16,Float64,Float16 -r 0,5 -m vtk - -.. figure:: ./figs/vtk_temp.png - - Visualization using paraview of the grid and temperature after 25 years of CO2 injection. - -.. note:: - - It is possible to write directly VTKs from OPM Flow simulations by adding the flag **\-\-enable-vtk-output=true**. - However, there are quantities that are not written (e.g., fipnum, flores), in addition to quantities not supported - such as component mass (e.g., co2, h2o). This is when **plopm** can be helpful. - -.. tip:: - - All previous commands can be executed as (`docs_convert_to_vtk.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_convert_to_vtk.sh - -================================ -Rel perms and capillary pressure -================================ - -**plopm** supports the plotting of saturation functions using the '-v' flag, namely 'krw', 'krg', 'krow', 'krog', 'pcow', 'pcog', and 'pcwg'. -By default, the saturation function is plotted for SATNUM=1. For a different table, this can be achieved by adding the number at the end of the variable, e.g., 'pcog5'. -In addition, if the model includes hysteresis, then to plot both drainage and imbibition curves this can be achieved by adding 'h' at the end of the variable, e.g., 'krg3h'. -However, by plotting individually the drainage and imbibition tables one can set the labels, colors, and styles for each of them. - -.. code-block:: bash - - plopm -i 'H2HYSTERESIS' -v krgh,krwh -llb "Hydrogen Brine" -c r,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl ' Liquid saturation, $s_w$ [-]' -ls solid,solid -xnt 6 -ynt 6 - plopm -i 'H2HYSTERESIS' -v krg1,krg2,krw1,krw2 -llb "Drainage hydrogen Imbibition hydrogen Drainage brine Imbibition brine" -c r,r,#0314fc,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,dashed,solid,dashed -xnt 6 -ynt 6 - plopm -i 'H2HYSTERESIS' -v pcwg -c k -x '[0,1]' -lw 5 -ll empty -fz 18 -fs 8,6 -yl 'Capillary pressure, $p_c$ [bar]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,dashed,solid,dashed -xnt 6 -ylog 1 - -.. image:: ./figs/saturation_functions.png - - -.. tip:: - - These figures can be generated by (`docs_rel_perms_and_capillary_pressure.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_rel_perms_and_capillary_pressure.sh - -=================================== -Different input files and ensembles -=================================== -Let us assume we have two different runs in different folders for the spe11b case, where the firsts results are save -in a folder called spe11b, and simulation results where the injection rate has been increased are saved in a folder -called spe11b_larger_inj. Then, to plot the summary vector for both runs we can execute: - -.. code-block:: bash - - plopm -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B' -v 'fgmip,fgmip / 1E6,RGMDS:5' -yl '[kg] [Kt] [kg]' -tu w -fs 10,5 -c r,b -ls 'solid,dashed' -t 'Field gas mass in place Converted to kilotonns Dissolved CO$_2$ in facie 5' -fz 14 -sg 2,2 -rdl 1 -ll empty,empty,empty,center -fn comparison -.. image:: ./figs/comparison.png - :scale: 6% - -Here, using subplots, we plot the gas in place in kilograms, we convert this to kilotonnes, the dissolve CO2 mass in facie 5, and the time is shown in weeks. - -.. tip:: - For any summary variable, one can give the path to more than two different simulation cases, just by separating the folder paths by spaces in the -i. - -To look at the difference between these two simulations for the dynamic variable sgas at the restar step 3, this can be achieved by executing: - -.. code-block:: bash - - plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 - -.. image:: ./figs/sgas_diff.png - -To changue the colormap and setting the colorbar limits manually, this can be achieved by: - -.. code-block:: bash - - plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 -c tab20c_r -cl '[0,0.8]' -cbn 9 -cbf 0.1 -fn formated - -.. image:: ./figs/sgas_diff_edit.png - -The `ensemble folder `_ provides a `Python file `_ to generate two different -ensembles using `pyopmnearwell `_, where the residual gas saturation is randomly generated. - -.. tip:: - You can install `pyopmnearwell `_ by executing in the terminal: pip install git+https://github.com/cssr-tools/pyopmnearwell.git. - -Below are two of the generated figures after executing the script (additional figures are generated to show the functionality of the **-ens** flag): - -.. figure:: ./figs/ensemble.png - - Example of visualizing ensembles using **plopm** (example0.png and example3_formated.png respectively). - -.. tip:: - - All previous commands can be executed as (`docs_different_files_and_ensembles.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_different_files_and_ensembles.sh - -======= -Filters -======= -Using the flag **-flt** allows to remove cells given conditions separated by '&', and it is also possible to set different filters in subfigures. For example: - -.. code-block:: bash - - plopm -i 'SPE11B SPE11B SPE11B' -flt ',fipnum >= 2 & fipnum != 4,satnum == 5' -v fipnum -sg 3,1 -rdl 1 -cbf .0f -fs 7,4 -u resdata -cbp 0.15,0.97,0.7,0.02 -t "No filter fipnum >= 2 and fipnum != 4 satnum == 5" -st 0 - -.. image:: ./figs/filter_opm.png - -.. note:: - - It is possible to set dynamic variables to filter as well such as sgas and pressure. However, this requires to output the dynamic pore volume, i.e., RPORV. - This can be achieved by adding to the deck RPORV to the RPTRST in the SOLUTION and SCHEDULE section (and running the simulations). - -.. tip:: - - All previous commands can be executed as (`docs_filters.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_filters.sh - -============ -GIF and mask -============ -To create a GIF and mask the results using the satnum numbers (any variable should be supported) for the different rock properties, this can be achieved by (here we have add -terminal commands to generate the data to generate figures by installing **pyopmspe11**, downloading the corresponding configuration files, creating one with higher injection -rate, and after using **plopm**): - -.. code-block:: bash - - pip install git+https://github.com/cssr-tools/pyopmspe11.git - curl -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml - cp spe11b.toml spe11b_larger_inj.toml - sed -i.bak 's/0.035/0.07/g' spe11b_larger_inj.toml && rm -fz spe11b_larger_inj.toml.bak - pyopmspe11 -i spe11b.toml -o spe11b -fz 0 - pyopmspe11 -i spe11b_larger_inj.toml -o spe11b_larger_inj -fz 0 - plopm -v xco2l -sg 1,2 -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B_LARGER_INJ' -fs 16,2.5 -mv satnum -r 0,1,2,3,4,5 -m gif -dpi 1000 -t "spe11b spe11b larger injection" -fz 16 -gi 1000 -gl 1 -cbf .2f -cbp 0.30,0.01,0.4,0.02 - -.. image:: ./figs/xco2l.gif - -If **-r** is not provided, then by default the GIF uses all restart steps. For selected restart steps, these can be given separated by commas, e.g., **-r 1,4,5**. - -To generate a single GIF of the gas saturation without masking and showing the grid: - -.. code-block:: bash - - plopm -i 'spe11b/SPE11B' -v sgas -tu y -c cet_cwr -ge 'black,5e-3' -fs 16,5 -m gif -dpi 1000 -fz 20 -gi 1000 -gl 1 -cbf .2f -asp 0 -xu km -yu km -xf .1f -yf .1f -cbn 5 -cbl 'Gas saturation [-]' - -.. image:: ./figs/spe11b_sgas.gif - -Here we have changed the units for time from days to years using the **-tu** flag. To remove the dynamic times in the GIF, set **-tu empty**. - -.. tip:: - - All previous commands can be executed as (`docs_gif_mask.sh `_): - - .. code-block:: bash - - . ./tests/scripts/docs_gif_mask.sh - -================== -Graphical abstract -================== - -Here we describe how to generate the ilustrations in the `graphical abstract `_. -The first ilustration is generated from the SPE11B model using `pyopmspe11 `_: - -.. code-block:: bash - - pip install git+https://github.com/OPM/pyopmspe11.git - curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml - curl -L https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml -o spe11b_higher_rate.toml - ex -s +'51c|inj = [[25, 5, 1, 0.07, 10, 1, 0.07, 10]]' -c x spe11b_higher_rate.toml - sed -i.bak 's/0.035/0.07/g' spe11b_higher_rate.toml - pyopmspe11 -i spe11b.toml -o spe11b -fz 0 - pyopmspe11 -i spe11b_higher_rate.toml -o spe11b_higher_rate -fz 0 - plopm -i 'spe11b/SPE11B spe11b_higher_rate/SPE11B_HIGHER_RATE' -v 'fgmip * 1e-6' -c 'r,b' -tu y -xf .0f -lw 2 -label 'Base case Higher injection rate' -xnt 6 -yl 'Total CO$_2$ mass [Kt]' -fz 18 -t 'Comparing two runs of the SPE11B model' - -The ilustration in the middle is generated from the `NORNE_ATW2013.DATA `_ model: - -.. code-block:: bash - - git clone https://github.com/OPM/opm-data.git - flow opm-data//norne/NORNE_ATW2013.DATA --enable-dry-run=1 - plopm -i opm-data//norne/NORNE_ATW2013 -v permx -clog 1 -rot 65 -s ,,1 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -t "Top view of NORNE" -xu km -yu km -fz 16 -ge 'black,1e-2' -xf .1f -yf .1f -fs 8,8 - -The ilustration in the right is generated from the SPE11C model using `pyopmspe11 `_, specially the corner-point case with -more than a 100 million cells (`r4_cp_8m-8mish-8mish.toml `_). Since that -case requires a big computer (run with 1024 CPUs), then the steps below are applied to a version of the SPE11C model with fewer cells that can be run locally: - -.. code-block:: bash - - pip install git+https://github.com/OPM/pyopmspe11.git - curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11c.toml - pyopmspe11 -i spe11c.toml -o spe11c -fz 0 - plopm -i spe11c/SPE11C -v satnum,xco2l -vf UInt16,Float16 -r 0,5 -m vtk - -The above commands will generate the SPE11C.pvd, SPE11C-000.vtu, and SPE11C_0005.vtu files, which then can be open using `paraview `_, -and using the interactive GUI one can then obtain the most-rigthed figure in the abstract (e.g., using the facie numbers stored as satnum to add the background). - -.. tip:: + .. grid-item-card:: Graphical abstract + :link: example-graphical-abstract + :link-type: ref + :img-top: figs/plopm.png - All previous commands can be executed as (`docs_graphical_abstract.sh `_): + Reproduce the graphical abstract. - .. code-block:: bash +.. toctree:: + :hidden: + :maxdepth: 1 - . ./tests/scripts/docs_graphical_abstract.sh + examples/hello-world + examples/colormaps + examples/generic-deck + examples/transformations + examples/projections + examples/histograms + examples/caprock + examples/csv + examples/vtk + examples/relative-permeability + examples/ensembles + examples/filters + examples/animations + examples/graphical-abstract diff --git a/docs/_sources/examples/animations.rst.txt b/docs/_sources/examples/animations.rst.txt new file mode 100644 index 0000000..041c28a --- /dev/null +++ b/docs/_sources/examples/animations.rst.txt @@ -0,0 +1,63 @@ +.. _example-animations: + +GIFs and masks +============== + +Animate results and apply masks. + +Create a masked GIF comparing two cases. + +.. code-block:: console + + plopm -v xco2l -sg 1,2 -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B_LARGER_INJ' -fs 16,2.5 -mv satnum -r 0,1,2,3,4,5 -m gif -dpi 1000 -t 'spe11b spe11b larger injection' -fz 16 -gi 1000 -gl 1 -cbf .2f -cbp 0.30,0.01,0.4,0.02 + +.. figure:: ../figs/xco2l.gif + :align: center + :width: 90% + +Create an unmasked gas-saturation GIF with grid edges. + +.. code-block:: console + + plopm -i spe11b/SPE11B -v sgas -tu y -c cet_cwr -ge 'black,5e-3' -fs 16,5 -m gif -dpi 1000 -fz 20 -gi 1000 -gl 1 -cbf .2f -asp 0 -xu km -yu km -xf .1f -yf .1f -cbn 5 -cbl 'Gas saturation [-]' + +.. figure:: ../figs/spe11b_sgas.gif + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_gif_mask.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_gif_mask.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_gif_mask.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/caprock.rst.txt b/docs/_sources/examples/caprock.rst.txt new file mode 100644 index 0000000..7464b80 --- /dev/null +++ b/docs/_sources/examples/caprock.rst.txt @@ -0,0 +1,54 @@ +.. _example-caprock: + +Caprock integrity +================= + +Evaluate pressure limits. + +``limipres``, ``overpres``, and ``objepres`` support caprock-integrity analysis. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -s ',,1:22 ,,1:22' -v limipres,overpres -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 15,10 -c Spectral,spring -sg 1,2 -rdl 1 + plopm -i NORNE_ATW2013 -m csv -v objepres -s ',,1:22' + +.. figure:: ../figs/norne_atw2013_overpres_i,j,1:22_t64.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_caprock_integrity.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_caprock_integrity.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_caprock_integrity.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/colormaps.rst.txt b/docs/_sources/examples/colormaps.rst.txt new file mode 100644 index 0000000..4fa7ed2 --- /dev/null +++ b/docs/_sources/examples/colormaps.rst.txt @@ -0,0 +1,53 @@ +.. _example-colormaps: + +Colormaps +========= + +Use named, RGB, and HEX colormaps. + +Use :option:`plopm -c` with Matplotlib or Colorcet names, RGB values, or HEX colors. + +.. code-block:: console + + plopm -i SPE11B -v satnum,fipnum,disperc -c '193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130',cet_glasbey_bw,'#b6c406 #fffa86' -sg 3,1 -rdl 1 -cbn 3,6,2 -cbf .0f,.0f,.1f -fs 7,4 + +.. figure:: ../figs/spe11b_disperc_i,1,k_t5.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_colormaps.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_colormaps.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_colormaps.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/csv.rst.txt b/docs/_sources/examples/csv.rst.txt new file mode 100644 index 0000000..9529b68 --- /dev/null +++ b/docs/_sources/examples/csv.rst.txt @@ -0,0 +1,75 @@ +.. _example-csv: + +Reading CSV files +================= + +Combine CSV and OPM Flow data. + +Use :option:`plopm -cc` to combine CSV and OPM Flow data. + +.. code-block:: console + + plopm -v xco2l -i 'r1_Cart_10m/R1_CART_10M r1_Cart_10m/spe11b_spatial_map_500y' -cc ';1,2,5' -sg 2,1 -rdl 1 -r 100 -fs 10,3 -st 0 -t 'Simulation grid Reporting grid' -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f + +.. figure:: ../figs/spe11b_spatial_map_500y_xco2l_csv_t100.png + :align: center + :width: 90% + +Compare a CSV series with an OPM summary vector. + +.. code-block:: console + + plopm -i 'r1_Cart_10m/spe11b_time_series r1_Cart_10m/R1_CART_10M' -v ',BWPR:256,1,5' -cc '1,3;' -sf '1e-5,1' -ls 'solid,dotted' -lw '4,4' -yl 'Sensor pressure [bar]' -llb 'From CSV file From OPM Flow output file' -c 'r,k' + +.. figure:: ../figs/spe11b_time_series_BWPR-1944.png + :align: center + :width: 90% + +Compare several benchmark series. + +.. figure:: ../figs/spe11b_time_series_csv_ens.png + :align: center + :width: 90% + +Compare several benchmark spatial maps. + +.. figure:: ../figs/spe11b_spatial_map_250y_csv_csv_t-1.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_reading_csvs.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_reading_csvs.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_reading_csvs.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/ensembles.rst.txt b/docs/_sources/examples/ensembles.rst.txt new file mode 100644 index 0000000..d3167c1 --- /dev/null +++ b/docs/_sources/examples/ensembles.rst.txt @@ -0,0 +1,79 @@ +.. _example-ensembles: + +Different inputs and ensembles +============================== + +Compare cases and ensembles. + +Compare summary quantities from two simulations. + +.. code-block:: console + + plopm -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B' -v 'fgmip,fgmip / 1E6,RGMDS:5' -yl '[kg] [Kt] [kg]' -tu w -fs 10,5 -c r,b -ls 'solid,dashed' -t 'Field gas mass in place Converted to kilotonnes Dissolved CO$_2$ in facies 5' -fz 14 -sg 2,2 -rdl 1 -ll empty,empty,empty,center -fn comparison + +.. figure:: ../figs/comparison.png + :align: center + :width: 90% + +Subtract one case from another. + +.. code-block:: console + + plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 + +.. figure:: ../figs/sgas_diff.png + :align: center + :width: 90% + +Format the difference map. + +.. code-block:: console + + plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 -c tab20c_r -cl '[0,0.8]' -cbn 9 -cbf 0.1 -fn formated + +.. figure:: ../figs/sgas_diff_edit.png + :align: center + :width: 90% + +Use :option:`plopm -ens` for ensemble statistics. + +.. figure:: ../figs/ensemble.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_different_files_and_ensembles.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_different_files_and_ensembles.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_different_files_and_ensembles.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/filters.rst.txt b/docs/_sources/examples/filters.rst.txt new file mode 100644 index 0000000..2cb938b --- /dev/null +++ b/docs/_sources/examples/filters.rst.txt @@ -0,0 +1,55 @@ +.. _example-filters: + +Filters +======= + +Select cells with conditions. + +Join conditions for one input with ``&`` and separate input filters with commas. + +.. code-block:: console + + plopm -i 'SPE11B SPE11B SPE11B' -flt ',fipnum >= 2 & fipnum != 4,satnum == 5' -v fipnum -sg 3,1 -rdl 1 -cbf .0f -fs 7,4 -cbp 0.15,0.97,0.7,0.02 -t 'No filter fipnum >= 2 and fipnum != 4 satnum == 5' -st 0 + +.. figure:: ../figs/filter_opm.png + :align: center + :width: 90% + +Dynamic filters require ``RPORV`` in ``RPTRST``. + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_filters.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_filters.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_filters.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/generic-deck.rst.txt b/docs/_sources/examples/generic-deck.rst.txt new file mode 100644 index 0000000..afbfb46 --- /dev/null +++ b/docs/_sources/examples/generic-deck.rst.txt @@ -0,0 +1,64 @@ +.. _example-generic-deck: + +Generic deck +============ + +Plot a generic OPM Flow model. + +Plot vertical permeability from SPE10 MODEL 2. + +.. code-block:: console + + plopm -i SPE10_MODEL2 -v permz -s ,4, -clog 1 -xu km -yu km -xnt 6 -yf .2f -t 'K$_z$ at the fourth slice in the xz plane' -cl '[1e-7,1e3]' + +.. figure:: ../figs/spe10_model2_permz_*,4,*_t0.png + :align: center + :width: 90% + +Plot the grid and wells from above. + +.. code-block:: console + + plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v grid -hide 0,0,1,0 + plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v wells -hide 0,0,0,1 + +.. figure:: ../figs/wells.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_generic_deck.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_generic_deck.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_generic_deck.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/graphical-abstract.rst.txt b/docs/_sources/examples/graphical-abstract.rst.txt new file mode 100644 index 0000000..9b74140 --- /dev/null +++ b/docs/_sources/examples/graphical-abstract.rst.txt @@ -0,0 +1,74 @@ +.. _example-graphical-abstract: + +Graphical abstract +================== + +Reproduce the graphical abstract. + +The graphical abstract combines an SPE11B summary comparison, a Norne map, and an SPE11C VTK visualization. + +.. figure:: ../figs/plopm.png + :align: center + :width: 90% + + The plopm graphical abstract. + +Generate the SPE11B comparison. + +.. code-block:: console + + plopm -i 'spe11b/SPE11B spe11b_higher_rate/SPE11B_HIGHER_RATE' -v 'fgmip * 1e-6' -c 'r,b' -tu y -xf .0f -lw 2 -llb 'Base case Higher injection rate' -xnt 6 -yl 'Total CO$_2$ mass [Kt]' -fz 18 -t 'Comparing two runs of the SPE11B model' + +Generate the Norne map. + +.. code-block:: console + + git clone https://github.com/OPM/opm-data.git + flow opm-data/norne/NORNE_ATW2013.DATA --enable-dry-run=1 + plopm -i opm-data/norne/NORNE_ATW2013 -v permx -clog 1 -rot 65 -s ,,1 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -t 'Top view of NORNE' -xu km -yu km -fz 16 -ge 'black,1e-2' -xf .1f -yf .1f -fs 8,8 + +Generate SPE11C VTK files. + +.. code-block:: console + + pip install git+https://github.com/OPM/pyopmspe11.git + curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11c.toml + pyopmspe11 -i spe11c.toml -o spe11c -fz 0 + plopm -i spe11c/SPE11C -v satnum,xco2l -vf UInt16,Float16 -r 0,5 -m vtk + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_graphical_abstract.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_graphical_abstract.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_graphical_abstract.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/hello-world.rst.txt b/docs/_sources/examples/hello-world.rst.txt new file mode 100644 index 0000000..061a8e5 --- /dev/null +++ b/docs/_sources/examples/hello-world.rst.txt @@ -0,0 +1,83 @@ +.. _example-hello-world: + +Hello world +=========== + +Create maps, summary plots, and cell time series. + +Run the default command from the ``examples`` directory. + +.. code-block:: console + + plopm -i SPE11B + +.. figure:: ../figs/spe11b_satnum_*,1,*_t5.png + :align: center + :width: 90% + +Plot gas saturation at restart step 4. + +.. code-block:: console + + plopm -i SPE11B -v sgas -r 4 -cbn 3 -c cubehelix -cbt '[0, middle, 0.9]' + +.. figure:: ../figs/spe11b_sgas_i,1,k_t4.png + :align: center + :width: 90% + +Plot field gas in place. + +.. code-block:: console + + plopm -i SPE11B -v fgip -c b -ls dotted -fz 12 -fs 5,5 -lw 4 -tu dates + +.. figure:: ../figs/fgip.png + :align: center + :width: 90% + +Plot pressure increase at three cells. + +.. code-block:: console + + plopm -i 'SPE11B SPE11B SPE11B' -v 'pressure - 0pressure' -s '1,1,1 41,1,29 83,1,58' -llb 'Top left corner Middle Right lower corner' -yl 'Pressure increase at the sensor locations [bar]' -yf .0f -xnt 11 -tu dates + +.. figure:: ../figs/spe11b_pressure-0pressure.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_hello_world.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_hello_world.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_hello_world.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/histograms.rst.txt b/docs/_sources/examples/histograms.rst.txt new file mode 100644 index 0000000..2231358 --- /dev/null +++ b/docs/_sources/examples/histograms.rst.txt @@ -0,0 +1,53 @@ +.. _example-histograms: + +Histograms +========== + +Plot property distributions. + +Plot porosity and permeability histograms with fitted distributions. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -v poro,permx -hist '20,norm 20,lognorm' -ag 0 -sg 1,2 -fs 15,5 -ll 'upper center' -y '[0,10000] [0,23000]' -c '#7274b3,#cddb6e' + +.. figure:: ../figs/norne_atw2013_permx.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_histograms.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_histograms.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_histograms.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/projections.rst.txt b/docs/_sources/examples/projections.rst.txt new file mode 100644 index 0000000..6a11f7a --- /dev/null +++ b/docs/_sources/examples/projections.rst.txt @@ -0,0 +1,53 @@ +.. _example-projections: + +Projections and subfigures +========================== + +Combine projection methods in one figure. + +Apply a different aggregation to each projected quantity. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -v 'index_k,permx,poro' -s ',,1:22 ,,1:22 ,,1:22' -agg 'first,arithmetic,max' -sg 1,3 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 24,10 -c 'PuOr,vanimo,jet' -cbf '.0f,.0f,.2f' -cbn '2,4,8' -st 0 -t 'Top k values using first Averaged permx using arithmetic Values of porosity using max' -fz 18 + +.. figure:: ../figs/norne_atw2013_poro_i,j,1:22_t64.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_projections_subfigures.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_projections_subfigures.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_projections_subfigures.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/relative-permeability.rst.txt b/docs/_sources/examples/relative-permeability.rst.txt new file mode 100644 index 0000000..d5148cd --- /dev/null +++ b/docs/_sources/examples/relative-permeability.rst.txt @@ -0,0 +1,54 @@ +.. _example-relative-permeability: + +Relative permeability and capillary pressure +============================================ + +Plot saturation functions. + +Append a SATNUM table number or ``h`` for hysteresis curves. + +.. code-block:: console + + plopm -i H2HYSTERESIS -v krgh,krwh -llb 'Hydrogen Brine' -c r,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,solid -xnt 6 -ynt 6 + plopm -i H2HYSTERESIS -v pcwg -c k -x '[0,1]' -lw 5 -ll empty -fz 18 -fs 8,6 -yl 'Capillary pressure, $p_c$ [bar]' -xl 'Liquid saturation, $s_w$ [-]' -xnt 6 -ylog 1 + +.. figure:: ../figs/saturation_functions.png + :align: center + :width: 90% + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_rel_perms_and_capillary_pressure.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_rel_perms_and_capillary_pressure.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_rel_perms_and_capillary_pressure.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/transformations.rst.txt b/docs/_sources/examples/transformations.rst.txt new file mode 100644 index 0000000..f109312 --- /dev/null +++ b/docs/_sources/examples/transformations.rst.txt @@ -0,0 +1,89 @@ +.. _example-transformations: + +Rotation, translation, and zoom +=============================== + +Transform, crop, and inspect Norne. + +Start with the Norne top view. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -s ,,1 + +.. figure:: ../figs/norne.png + :align: center + :width: 90% + +Rotate, translate, and crop the grid. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -fz 8 + +.. figure:: ../figs/norne_transformed.png + :align: center + :width: 90% + +Apply the same transformation to faults. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -v faults -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 + plopm -i NORNE_ATW2013 -v faults -s ,,1:22 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -agg max + +.. figure:: ../figs/norne_faults.png + :align: center + :width: 90% + +Plot all wells and wells on the selected layer. + +.. code-block:: console + + plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 -fn norne_wells_global + plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -fn norne_wells + +.. figure:: ../figs/norne_wells.png + :align: center + :width: 90% + +.. note:: + + Faults and wells must be declared directly in the input deck. + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_rotation_translation_zoom.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_rotation_translation_zoom.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_rotation_translation_zoom.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/examples/vtk.rst.txt b/docs/_sources/examples/vtk.rst.txt new file mode 100644 index 0000000..0c5c96a --- /dev/null +++ b/docs/_sources/examples/vtk.rst.txt @@ -0,0 +1,55 @@ +.. _example-vtk: + +Convert to VTK +============== + +Export data for `ParaView `_. + +Export selected variables for restart steps 0 and 5. + +.. code-block:: console + + plopm -i SPE11B -v temp,fipnum,co2m,xco2l -vf Float32,UInt16,Float64,Float16 -r 0,5 -m vtk + +.. figure:: ../figs/vtk_temp.png + :align: center + :width: 90% + + Grid and temperature after 25 years of CO2 injection, viewed in ParaView. + +Reproduce this example +---------------------- + +Run the complete workflow from the repository root: + +.. code-block:: console + + . ./tests/scripts/docs_convert_to_vtk.sh + +.. grid:: 1 2 2 2 + :gutter: 2 + + .. grid-item:: + + .. button-link:: https://github.com/cssr-tools/plopm/blob/main/tests/scripts/docs_convert_to_vtk.sh + :color: primary + :outline: + :expand: + + View script + + .. grid-item:: + + .. button-link:: https://raw.githubusercontent.com/cssr-tools/plopm/main/tests/scripts/docs_convert_to_vtk.sh + :color: secondary + :outline: + :expand: + + View raw script + +.. button-ref:: examples-gallery + :ref-type: ref + :color: primary + :outline: + + Back to the examples gallery diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index ac35721..1f15f2a 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -1,22 +1,104 @@ -.. plopm documentation master file +plopm +===== -Welcome to plopm's documentation! -================================= +.. rst-class:: lead + + A lightweight and flexible tool for visualization and postprocessing of + OPM Flow geological models. + +**plopm** generates publication-ready PNG figures, GIF animations, CSV data, +and VTK files from OPM Flow simulation output. + +.. grid:: 1 2 2 4 + :gutter: 3 + :margin: 4 0 4 0 + + .. grid-item-card:: :octicon:`rocket;1.2em` Get started + :link: introduction + :link-type: doc + + Learn what **plopm** does and where to begin. + + .. grid-item-card:: :octicon:`download;1.2em` Install plopm + :link: installation + :link-type: doc + + Install **plopm** and the optional OPM Flow and LaTeX dependencies. + + .. grid-item-card:: :octicon:`book;1.2em` Follow the tutorial + :link: tutorial + :link-type: doc + + Progress from a first PNG to projections, comparisons, and data export. + + .. grid-item-card:: :octicon:`image;1.2em` Explore examples + :link: examples + :link-type: doc + + Browse task-oriented examples with figures and reproducible scripts. + +Quick installation +------------------ + +Install the current development version from GitHub: + +.. code-block:: console + + pip install git+https://github.com/cssr-tools/plopm.git + +See :doc:`installation` for virtual environments, source installation, OPM +Flow, and optional LaTeX support. + +Quick start +----------- + +Plot pressure on the plane at ``j=1``: + +.. code-block:: console + + plopm -i SPE11B -v pressure -s ,1, + +Display the built-in help or list the variables available for an input case: + +.. code-block:: console + + plopm --help + plopm -i SPE11B -lv 1 + +See the :doc:`tutorial` for a guided workflow and the :doc:`command-line` for +exact syntax and option descriptions. + +What can plopm do? +------------------ + +.. grid:: 1 2 2 2 + :gutter: 3 + + .. grid-item-card:: Plot reservoir properties + + Visualize static and dynamic quantities on model slices and projections. + + .. grid-item-card:: Compare simulations + + Plot multiple cases, differences, summary vectors, and ensembles. + + .. grid-item-card:: Create reusable outputs + + Export PNG figures, GIF animations, CSV data, and VTK datasets. + + .. grid-item-card:: Support reproducible workflows + + Reproduce visualization and postprocessing tasks from shell scripts. .. toctree:: - :maxdepth: 4 + :hidden: + :maxdepth: 2 introduction installation + tutorial examples + command-line api contributing related - about - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/_sources/installation.rst.txt b/docs/_sources/installation.rst.txt index 5bceac2..73a00e6 100644 --- a/docs/_sources/installation.rst.txt +++ b/docs/_sources/installation.rst.txt @@ -1,121 +1,186 @@ -============ +.. _installation: + Installation ============ -The following steps work installing the dependencies in Linux via apt-get or in macOS using brew or macports. -While using packages managers such as Anaconda, Miniforge, or Mamba might work, these are not tested. -The supported Python versions are 3.12 to 3.14. +The following instructions cover dependency installation on Linux with +``apt-get`` and on macOS with Homebrew or MacPorts. Package managers such as +Anaconda, Miniforge, and Mamba might work, but they are not tested. + +**plopm** supports Python 3.12 to 3.14. .. _vplopm: Python package -------------- -To install the **plopm** executable from the development version in an existing Python environment: +Install the development version of **plopm** in an existing Python +environment: -.. code-block:: bash +.. code-block:: console - pip install git+https://github.com/cssr-tools/plopm.git + pip install git+https://github.com/cssr-tools/plopm.git -If you are interested in a specific version (e.g., v2026.04) or in modifying the source code, then you can clone the repository and -install the Python requirements in a virtual environment with the following commands: +To install a specific version, modify the source code, or contribute to the +project, clone the repository and create a virtual environment: .. code-block:: console - # Clone the repo - git clone https://github.com/cssr-tools/plopm.git - # Get inside the folder - cd plopm - # For a specific version (e.g., v2026.04), or skip this step (i.e., edge version) - git checkout v2026.04 - # Create virtual environment - python3 -m venv vplopm - # Activate virtual environment - source vplopm/bin/activate - # Upgrade pip, setuptools, and wheel - pip install --upgrade pip setuptools wheel - # Install the plopm package - pip install -e . - # For contributions/testing/linting, install the dev-requirements - pip install -r dev-requirements.txt + # Clone the repository + git clone https://github.com/cssr-tools/plopm.git + + # Enter the repository + cd plopm + + # Optional: select a release, or skip this step to use the development version + git checkout v2026.04 + + # Create a virtual environment + python3 -m venv vplopm + + # Activate the virtual environment + source vplopm/bin/activate + + # Upgrade the packaging tools + pip install --upgrade pip setuptools wheel + + # Install plopm in editable mode + pip install -e . + + # Optional: install requirements for contributions, testing, and linting + pip install -r dev-requirements.txt .. tip:: - Typing **git tag -l** writes all available specific versions. + Run ``git tag -l`` to list the available releases. + +Optional LaTeX formatting +------------------------- + +LaTeX support is optional but recommended for figure formatting. + +On Linux distributions using ``apt-get``, install: -.. note:: - - For not macOS users, to install the (optional but recommended) dependencies used for the figure's LaTeX formatting, execute - - **sudo apt-get install texlive-fonts-recommended texlive-fonts-extra dvipng cm-super** +.. code-block:: console + + sudo apt-get install texlive-fonts-recommended texlive-fonts-extra dvipng cm-super + +On macOS, install `MacTeX `_. - For macOS users, the LaTeX dependency can be installed from https://www.tug.org/mactex/. +.. _opm-flow-installation: OPM Flow -------- -To use the convertion from OPM Flow output files (i.e., .EGRID, .INIT, .UNRST) to vtk, you also need to install: -* OPM Flow (https://opm-project.org, Release 2026.04 or current master branches) +OPM Flow is required to convert OPM Flow output files such as ``.EGRID``, +``.INIT``, and ``.UNRST`` to VTK. Use OPM Flow Release 2026.04 or the current +master branches. + +See the `OPM project website `_ for general +information. Binary packages +++++++++++++++ -See the `downloading and installing `_ OPM Flow online documentation for -instructions to install the binary packages in Ubuntu and Red Hat Enterprise Linux, and for other platforms which are -supported either via source builds or through running a virtual machine. +See the OPM Flow `download and installation instructions +`_ for binary packages on Ubuntu and Red +Hat Enterprise Linux. The same page describes other supported platforms, +including source builds and virtual-machine-based installations. .. tip:: - See the `CI.yml `_ script - for installation of OPM Flow (binary packages), LaTeX (optional) libraries, and the plopm package in Ubuntu 26.04 and Python 3.14. + The plopm `CI workflow + `_ + shows the installation of OPM Flow binary packages, optional LaTeX + libraries, and **plopm** on Ubuntu 26.04 with Python 3.14. -Source build in Linux/Windows -+++++++++++++++++++++++++++++ -If you are a Linux user (including the Windows subsystem for Linux), then you could try to build Flow (after installing the `prerequisites `_) from the master branches with mpi support by running -in the terminal the following lines (which in turn should build flow in the folder ./build/opm-simulators/bin/flow): +Source build on Linux ++++++++++++++++++++++ -.. code-block:: console +After installing the OPM `prerequisites +`_, build Flow from the current master +branches with MPI support. The following commands create the executable at +``./build/opm-simulators/bin/flow``: + +.. code-block:: bash - CURRENT_DIRECTORY="$PWD" + CURRENT_DIRECTORY="$PWD" - mkdir build + mkdir build - for repo in common grid simulators - do git clone https://github.com/OPM/opm-$repo.git - mkdir build/opm-$repo - cd build/opm-$repo - cmake -DUSE_MPI=1 -DWITH_NDEBUG=1 -DCMAKE_BUILD_TYPE=Release $CURRENT_DIRECTORY/opm-$repo - if [[ $repo == simulators ]]; then - make -j5 flow - else - make -j5 opm$repo - fi - cd ../.. - done + for repo in common grid simulators + do + git clone https://github.com/OPM/opm-$repo.git + mkdir build/opm-$repo + cd build/opm-$repo + cmake -DUSE_MPI=1 -DWITH_NDEBUG=1 -DCMAKE_BUILD_TYPE=Release $CURRENT_DIRECTORY/opm-$repo + if [[ $repo == simulators ]]; then + make -j5 flow + else + make -j5 opm$repo + fi + cd ../.. + done .. tip:: - You can create a .sh file (e.g., build_opm_mpi.sh), copy the previous lines, and run in the terminal **. ./build_opm_mpi.sh** + Save the commands in a shell script, for example + ``build_opm_mpi.sh``, and run it with: + + .. code-block:: console + + . ./build_opm_mpi.sh + +The resulting Flow executable can be selected explicitly when generating VTK +files: + +.. code-block:: console + + plopm -i SPE11C -m vtk -fp ./build/opm-simulators/bin/flow + +See :option:`plopm -fp` and :ref:`options-vtk`. .. _macOS: -Brew formula for macOS -++++++++++++++++++++++ -For macOS, there are no available binary packages, so OPM Flow needs to be built from source. Recently, a formula to build flow using brew has -been added in `https://github.com/cssr-tools/homebrew-opm `_. -Then, you can try to install flow (v2026.07 interim release) by simply typing: +Homebrew formula for macOS +++++++++++++++++++++++++++ + +Binary OPM Flow packages are not available for macOS, so Flow must be built +from source. The `cssr-tools/homebrew-opm +`_ repository provides a Homebrew +formula for this purpose. + +Install the OPM Flow v2026.07 interim release with: .. code-block:: console - brew tap cssr-tools/opm - brew trust cssr-tools/opm - brew install cssr-tools/opm/opm-simulators -y + brew tap cssr-tools/opm + brew trust cssr-tools/opm + brew install cssr-tools/opm/opm-simulators -y + +Verify the installation: + +.. code-block:: console -You can check if the installation of OPM Flow succeded by typing in the terminal **flow \-\-help**. + flow --help .. tip:: - See the actions in the `cssr-tools/homebrew-opm `_ repository. -Source build in macOS + See the `homebrew-opm workflow results + `_ for tested builds. + +Source build on macOS +++++++++++++++++++++ -See `this repository `_ dedicated to build OPM Flow from source in macOS 26 (GitHub actions), and tested with **pycopm**, another repository in cssr-tools. + +See the `OPM-Flow_macOS repository +`_ for a source-build workflow for +OPM Flow on macOS 26. The workflow runs with GitHub Actions and is tested with +**pycopm**, another project in the ``cssr-tools`` organization. + +Next steps +---------- + +* Follow the :doc:`tutorial` to progress from a first PNG to SPE11C + projections and comparisons. +* Browse the :doc:`examples` for task-oriented workflows. +* Use the :doc:`command-line` for syntax and option descriptions. diff --git a/docs/_sources/introduction.rst.txt b/docs/_sources/introduction.rst.txt index cebeae0..59db810 100644 --- a/docs/_sources/introduction.rst.txt +++ b/docs/_sources/introduction.rst.txt @@ -1,608 +1,55 @@ -============ -Introduction -============ - -.. image:: ./figs/plopm.png - -This documentation describes the **plopm** tool hosted in `https://github.com/cssr-tools/plopm `_. - -Concept -+++++++ -Simplified and flexible framework for quick visualization of `OPM Flow `_ geological models. -The approach is the generation of PNG figures from static (e.g, porosity, pore volume fluid in place numbers) -and dynamic (e.g., pressure, fluid saturations) properties given any 2D slide with the option to generate GIFs (e.g., the middle part of a reservoir in the xy plane), -as well as plotting any given summary vector (e.g., field gas in place a.k.a fgip). - -The **plopm** tool can be useful for quick inspection of geological models, as well as for generation of nice -figures for papers/presentations. Also, **plopm** can plot summary results from different simulation cases in the same figure (e.g., using subplots), -as well as the difference between given dynamic variables (e.g., pressure) for two different simulations cases. In addition, **plopm** can -convert OPM Flow output files to vtk, which allows to use other visualization/postprocessing tools (e.g., `paraview `_). +.. _introduction: -.. _overview: +.. image:: figs/plopm.png -Command-line interface -++++++++++++++++++++++ - -plopm provides command-line options for selecting input data, configuring -plots, and controlling output. Run the following command to display the -available options and their default values: +Introduction +============ -.. code-block:: console +**plopm** is a lightweight command-line tool for visualization and +postprocessing of OPM Flow geological models. - plopm -h +It can generate: +* two-dimensional maps of static and dynamic quantities; +* summary plots and comparisons between simulation cases; +* PNG figures and GIF animations; +* CSV data for further analysis; +* VTK files for three-dimensional visualization. Basic usage ----------- -The general command structure is: - -.. code-block:: console - - plopm [options] - -.. tip:: - - The options have both a short and a long name. For example, ``-v`` and - ``--variable`` refer to the same option: - - .. code-block:: console - - plopm -v pressure - plopm --variable pressure - - The short form is convenient for interactive use, while the long form can - make scripts and saved commands easier to understand. The examples in this - documentation use the short forms. - -For example, the following command plots pressure and gas saturation from -``SPE11B`` at the last restart step: - -.. code-block:: console - - plopm -i SPE11B -v "pressure,sgas" -r -1 - -Options may be combined to configure the data selection, plot appearance, -and output. For example: - -.. code-block:: console - - plopm -i SPE11B -v pressure -s ",,5" -c viridis -cl "[100,300]" -o results -fn pressure_k5 - - -Argument syntax ---------------- - -Many plopm options accept multiple values or specifications. Commas normally -separate components within one specification, while spaces separate repeated -specifications for different inputs, variables, or plots. Enclose the complete -argument in quotes when it contains spaces. - -For example: +A typical command selects an input case, a variable, and a model slice: .. code-block:: console - plopm -v "pressure,sgas" - plopm -s "1,1,1 41,1,29 83,1,58" - plopm -y "[0,10000] [0,23000]" - plopm -hist "50,norm 20,lognorm 100" - plopm -clog "1,1,0" - -The separators have the following general meanings: - -* **Commas** separate components within one specification, such as - ``2,4,9``, ``0,2,5``, or ``[100,-50]``. -* **Single spaces** separate repeated specifications, such as - ``1,1,1 41,1,29 83,1,58`` or ``[0,10000] [0,23000]``. -* **Two spaces** separate free-text labels or titles when each value may - contain spaces, such as ``Reference case Modified case``. -* **Semicolons** separate CSV column specifications for different inputs. - An empty specification skips the corresponding input, such as ``;1,2,5``. -* **Ampersands (``&``)** join filter conditions for the same input. -* **Commas in ``-flt``** separate filter specifications for different - inputs. -* **Empty entries** act as placeholders when an option applies only to - selected inputs. - -For example: - -.. code-block:: console - - plopm -llb "Reference case Modified case" - plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5" - plopm -i "table model" -v ",BWPR:256,1,5" -cc "1,3;" - - -Option reference ----------------- - -The options are grouped by purpose. Default values are also displayed by -``plopm --help``. - -.. note:: - - Legacy option names from earlier plopm releases remain available for - backward compatibility. The documentation uses the preferred option names. - - -Input and data selection -~~~~~~~~~~~~~~~~~~~~~~~~ - -``-i``, ``--input`` - Base name or full path of the input. Separate multiple inputs with spaces, - e.g., ``SPE11B /home/user/SPE11B_TUNED`` (``SPE11B`` by default). - -``-v``, ``--variable`` - Variable specification(s) to plot. Separate variables with commas, e.g., - ``pressure,sgas``. - - An empty entry may be used as a placeholder when the corresponding input - is configured through ``-cc``, e.g.: - - .. code-block:: console - - plopm -v ",BWPR:256,1,5" -cc "1,3;" - - Special variables include ``grid``, ``wells``, ``faults``, ``pcfact``, - ``limipres``, ``overpres``, ``objepres``, ``krw``, ``krg``, ``krow``, - ``krog``, ``pcow``, ``pcog``, ``pcwg``, ``gasm``, ``dism``, ``liqm``, - ``vapm``, ``co2m``, ``h2om``, ``xco2l``, ``xh2ov``, ``xco2v``, - ``xh2ol``, ``fwcdm``, and ``fgipm``. - - The default is - ``poro,permx,permz,porv,fipnum,satnum``. - -``-r``, ``--restart`` - Restart step(s), where ``0`` is the initial state and ``-1`` is the last. - Separate selected steps with commas, e.g., ``0,2`` or ``0,3,10,20``, or - use ``start:end[:step]``, e.g., ``1:3``, ``0:4:2``, or ``5:505:250``. - - The default is ``-1``. GIF output uses all available steps by default. - -``-cc``, ``--csv-columns`` - CSV column indices, starting at 1. Use ``t,value`` for a time series or - ``x,y,value`` for a spatial map. - - Separate specifications for different inputs with semicolons. An empty - specification skips the corresponding input, e.g., ``;1,2,5`` or - ``1,3;`` (empty by default). - -``-fp``, ``--flow-path`` - Path or command for the Flow executable, e.g., - ``/home/build/bin/flow``. Used only to generate the grid for VTK output - (``flow`` by default). - - -Output options -~~~~~~~~~~~~~~ - -``-m``, ``--format`` - Output format: ``png``, ``gif``, ``csv``, or ``vtk`` - (``png`` by default). - -``-o``, ``--output-dir`` - Base name or full path of the output directory. The default is ``.``, - meaning the directory where plopm is executed. - -``-fn``, ``--filename`` - Output file name. The default is empty, meaning that the name is set by - plopm. - - -Spatial and temporal selection -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-s``, ``--slice`` - Spatial selection in ``i,j,k`` form. An empty entry selects a plane, e.g., - ``10,,``; a range projects over cells, e.g., ``,,5:10``; ``:`` selects a - line, e.g., ``:,5,7``; and three indices select a cell over time, e.g., - ``2,4,9``. - - Separate multiple selections with spaces, e.g.: - - .. code-block:: console - - plopm -s "1,1,1 41,1,29 83,1,58" - - The default is ``,1,``. - -``-tu``, ``--time-units`` - Summary-plot x-axis time units: ``s``, ``m``, ``h``, ``d``, ``w``, ``y``, - ``dates``, ``empty``, or ``tstep`` (``d`` by default). - -``-dist``, ``--distance`` - Compute the minimum or maximum distance to a sensor or lateral border. - Supported specifications are ``min,sensor``, ``max,sensor``, - ``min,border``, and ``max,border``. - - For a sensor, provide its ``i,j,k`` location with ``-s``, e.g.: - - .. code-block:: console - - plopm -s 1,2,3 -v "sgas > 1e-2" -dist max,sensor - - The default is empty, meaning that no distance is computed. - - -Filtering, masking, and thresholds -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-flt``, ``--filters`` - Cell-selection conditions. Join conditions for one input with ``&`` and - separate filters for different inputs with commas, e.g.: - - .. code-block:: console - - plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5" - - The default is empty. Dynamic variables such as ``sgas`` require ``RPORV`` - in ``RPTRST``. - -``-vmin``, ``--min-threshold`` - Minimum threshold used to remove variable values (empty by default). - -``-vmax``, ``--max-threshold`` - Maximum threshold used to remove variable values (empty by default). - -``-mv``, ``--mask-variable`` - Static variable used as the background of a 2D map (empty by default). - -``-mt``, ``--mask-threshold`` - Threshold applied to the variable supplied through ``-mv`` - (``1e-3`` by default). - - -Computation and data transformation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-agg``, ``--aggregation`` - Aggregation or selection method for 2D slices and projections. Supported - values are ``min``, ``max``, ``sum``, ``mean``, ``pvmean``, ``harmonic``, - ``arithmetic``, ``first``, and ``last``. - - Separate methods for multiple variables or plots with commas, e.g.: - - .. code-block:: console - - plopm -agg "first,arithmetic,max" - - By default, continuous variables are pore-volume weighted, extensive - quantities are summed, indices retain discrete values, and permeabilities - use directional harmonic or arithmetic averaging. - - For wells and faults, ``min`` shows cells containing at least one - occurrence, while ``max`` requires all projected cells to contain one. - The default is empty, meaning that the method is selected automatically. - -``-sf``, ``--scale-factor`` - Multiplicative scaling factor applied to variable values, e.g., ``1e-9`` - to display CO2 mass in Mt. - - Separate factors for multiple variables or plots with commas, e.g., - ``1e-5,1`` (``1`` by default). - -``-di``, ``--difference-input`` - Base name or full path of the input model to subtract from the primary - input (empty by default). - -``-sc``, ``--stress-coefficient`` - Stress coefficient used to compute pressure limits for ``limipres``, - ``overpres``, and ``objepres`` (``0.134`` by default). - -``-dg``, ``--dual-grid`` - Enable dual-grid processing using ``0`` or ``1`` (``0`` by default). - - -Plot types and statistical representation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-hist``, ``--histogram`` - Histogram bins and optional distribution, e.g., ``20``, ``20,norm``, or - ``20,lognorm``. - - Separate specifications for multiple plots with spaces, e.g.: - - .. code-block:: console - - plopm -hist "50,norm 20,lognorm 100" - - The default is empty, meaning that no histogram is plotted. - -``-ens``, ``--ensemble`` - Ensemble plotting mode: - - * ``0`` disables ensemble plotting. - * ``1`` plots the mean and error bands. - * ``2`` plots the minimum, mean, and maximum. - * ``3`` plots both representations. - - The default is ``0``. - -``-fb``, ``--fill-between-style`` - Fill colors and alpha values used for ensemble error bands, supplied as - comma-separated pairs, e.g., ``r,0.1,g,0.2``. - - This option is used with ``-ens 1`` or ``-ens 3``. The default is empty, - meaning that the mean color is used with an alpha value of ``0.2``. - -``-sp``, ``--step-plot`` - Use ``ax.step`` instead of ``ax.plot``: ``0`` or ``1`` - (``0`` by default). - - -Figure and subplot layout -~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-fs``, ``--figsize`` - Figure width and height in inches, separated by a comma, e.g., ``8,16`` - (``7,5`` by default). - -``-sg``, ``--subplot-grid`` - Number of subplot rows and columns, separated by a comma, e.g., ``2,2`` - for four subplots. - - The default is empty, meaning that separate figures are created. - -``-cbp``, ``--colorbar-position`` - Global colorbar position and size as ``left,bottom,width,height``, e.g., - ``0.1,0.95,0.8,0.02``. - - Use ``empty`` to remove the global colorbar. The default is - ``0.2,0.01,0.6,0.02``. - -``-rdl``, ``--remove-duplicate-labels`` - Remove duplicated axis labels in subplot layouts using ``0`` or ``1`` - (``0`` by default). - - -Titles, labels, and legends -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-t``, ``--title`` - Figure title. Separate titles for multiple plots with two spaces - (``0`` by default). - - For example: - - .. code-block:: console - - plopm -t "Reference case Modified case" - -``-st``, ``--suptitle`` - Title for a group of subplots. Use ``0`` to remove it. The default is - empty, meaning that the title is set by plopm. - -``-xl``, ``--xlabel`` - X-axis label. Separate labels for multiple plots with two spaces. The - default is empty, meaning that labels are set by plopm. - -``-yl``, ``--ylabel`` - Y-axis label. Separate labels for multiple plots with two spaces. The - default is empty, meaning that labels are set by plopm. - -``-cbl``, ``--colorbar-label`` - Colorbar label. Separate labels for multiple plots with two spaces. The - default is empty, meaning that labels are set by plopm. - -``-llb``, ``--legend-labels`` - Summary-plot legend labels. Separate labels with two spaces, e.g.: - - .. code-block:: console - - plopm -llb "Reference case Modified case" - - The default is empty, meaning that labels are set by plopm. - -``-ll``, ``--legend-location`` - Legend location passed to ``matplotlib.pyplot.legend``. Supported values - are ``best``, ``upper right``, ``upper left``, ``lower left``, - ``lower right``, ``right``, ``center left``, ``center right``, - ``lower center``, ``upper center``, and ``center``. - - Use ``empty`` to remove the legend (``best`` by default). - -``-hide``, ``--hide-map-elements`` - Hide the left axis, bottom axis, colorbar, and title using four - comma-separated values of ``0`` or ``1``, in that order. - - For example, ``1,0,1,0`` hides the left axis and colorbar while retaining - the bottom axis and title. The default is ``0,0,0,0``. - - -Axes, coordinates, and formatting -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``-x``, ``--xlim`` - X-axis limits in the requested display order, e.g., ``[-100,200]`` or - ``[200,-100]``. - - Separate limits for multiple plots with spaces, e.g.: - - .. code-block:: console - - plopm -x "[-100,200] [500,0]" - - The default is empty. - -``-y``, ``--ylim`` - Y-axis limits in the requested display order, e.g., ``[0,70]`` or - ``[70,0]``. - - Separate limits for multiple plots with spaces, e.g.: - - .. code-block:: console - - plopm -y "[0,10000] [0,23000]" - - The default is empty. - -``-xu``, ``--xunits`` - Spatial-map x-axis units: ``mm``, ``cm``, ``m``, or ``km`` - (``m`` by default). - -``-yu``, ``--yunits`` - Spatial-map y-axis units: ``mm``, ``cm``, ``m``, or ``km`` - (``m`` by default). - -``-asp``, ``--equal-aspect`` - Scale the axes equally in 2D maps using ``0`` or ``1`` - (``1`` by default). - -``-rot``, ``--rotation`` - Grid rotation angle in degrees for 2D maps (``0`` by default). - -``-tr``, ``--translation`` - Grid translation in the x and y directions, e.g., ``[100,-50]`` - (``[0,0]`` by default). - -``-xlog``, ``--xlog`` - Enable the logarithmic x-axis using ``0`` or ``1``. - - Comma-separated settings are accepted when different plots require - different values (``0`` by default). - -``-ylog``, ``--ylog`` - Enable the logarithmic y-axis using ``0`` or ``1``. - - Comma-separated settings are accepted when different plots require - different values (``0`` by default). - -``-xf``, ``--xformat`` - X-axis number format, e.g., ``.2e``. The default is empty, meaning that - the format is set by plopm. - -``-yf``, ``--yformat`` - Y-axis number format, e.g., ``.1f``. The default is empty, meaning that - the format is set by plopm. - -``-xnt``, ``--xtick-count`` - Number of x-axis ticks (``5`` by default). - -``-ynt``, ``--ytick-count`` - Number of y-axis ticks (``5`` by default). - - -Color scales and styling -~~~~~~~~~~~~~~~~~~~~~~~~ - -``-c``, ``--colors`` - Colormap for spatial plots, e.g., ``jet``, or summary-plot colors - separated by commas, e.g., ``b,r``. - - The default is empty, meaning that colors are selected by plopm. - -``-cl``, ``--clim`` - Color-scale limits in the requested display order, e.g., ``[-0.1,11]`` or - ``[11,-0.1]``. - - Separate limits for multiple plots with spaces. The default is empty. - -``-clog``, ``--color-log`` - Enable logarithmic color scaling using ``0`` or ``1``. - - Separate settings for multiple variables with commas, e.g.: - - .. code-block:: console - - plopm -clog "1,1,0" - - The default is ``0``. - -``-clt``, ``--color-log-ticks`` - Tick values for logarithmic color scales, enclosed by brackets and - separated by commas, e.g., ``[1,10,100]``. - - At least one corresponding ``-clog`` setting must be ``1``. The default - is empty. - -``-gr``, ``--global-range`` - Use the value range of the current slice or the entire 3D model for color - scaling: - - * ``0`` uses the current slice range. - * ``1`` uses the whole-model range. - - The default is ``0``. - -``-cbf``, ``--colorbar-format`` - Colorbar number format, e.g., ``.2f``. The default is empty, meaning that - the format is set by plopm. - -``-cbn``, ``--colorbar-tick-count`` - Number of colorbar ticks. Separate values for multiple plots with commas, - e.g., ``3,6,2``. - - The default is empty, meaning that the number of ticks is set by plopm. - -``-cbt``, ``--colorbar-ticks`` - Custom colorbar tick labels enclosed by brackets and separated by commas, - e.g., ``[G,F,E,D,C,ESF]`` (empty by default). - -``-lw``, ``--linewidth`` - Line widths separated by commas, e.g., ``1,2,1.5``. The default is empty, - meaning that line widths are set by plopm. - -``-ls``, ``--linestyle`` - Line styles separated by commas, e.g., ``solid,dotted``. The default is - empty, meaning that line styles are set by plopm. - -``-ag``, ``--axis-grid`` - Display the summary-plot axis grid using ``0`` or ``1`` - (``1`` by default). - -``-fc``, ``--facecolor`` - Color outside the spatial map (``w`` by default, meaning white). - -``-ic``, ``--inactive-color`` - Color for inactive cells in 2D maps - (``w`` by default, meaning white). - -``-ge``, ``--grid-edges`` - ``pcolormesh`` edge color and line width separated by a comma, e.g., - ``black,1e-3``. - - The default is empty, meaning that cell edges are not displayed. - -``-fz``, ``--fontsize`` - Font size (``12`` by default). - -``-dpi``, ``--dpi`` - Figure resolution in dots per inch (``500`` by default). - - -VTK output -~~~~~~~~~~ - -The following options apply only when ``-m vtk`` is selected. - -``-vf``, ``--vtk-format`` - VTK data type for each variable. Supported formats are ``Float64``, - ``Float32``, ``Float16``, ``Int64``, ``UInt64``, ``Int32``, ``UInt32``, - ``Int16``, ``UInt16``, ``Int8``, and ``UInt8``. - - Separate formats for multiple variables with commas - (``Float64`` by default). - -``-vn``, ``--vtk-names`` - Custom VTK variable names separated by commas. The default is empty, - meaning that the names supplied through ``-v`` are used. - - -GIF output -~~~~~~~~~~ + plopm -i SPE11C -v pressure -s ,1, -The following options apply only when ``-m gif`` is selected. +This command plots pressure on the plane at ``j=1`` and writes a PNG to the +current directory. -``-gi``, ``--gif-interval`` - GIF frame interval in milliseconds (``1000`` by default). +Where to continue +----------------- -``-gl``, ``--gif-loop`` - Loop GIF animations indefinitely using ``0`` or ``1`` - (``0`` by default). +* See :doc:`installation` to install **plopm** and its optional dependencies. +* Follow the :doc:`tutorial` to progress from a first PNG to projections, + comparisons, animations, and data export. +* Browse the :doc:`examples` for complete visualization recipes. +* Use the :doc:`command-line` for syntax and option descriptions. +* See the :doc:`api` to use **plopm** from Python. +* See :doc:`contributing` to report issues, request features, or contribute to + **plopm**. +* Explore :doc:`related` for complementary open-source tools. +About the project +----------------- -Information and diagnostics -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**plopm** is funded by the `HPC Simulation Software for the Gigatonne +Storage Challenge project +`_ +(project number 622059) and the `Center for Sustainable Subsurface Resources +`_ (project number 331841). -``-lv``, ``--list-variables`` - Print the available variables using ``0`` or ``1`` (``0`` by default). +Contributions are welcome. See :doc:`contributing` to propose changes or +`open an issue `_ to +report a problem or request a feature. diff --git a/docs/_sources/options/axes.rst.txt b/docs/_sources/options/axes.rst.txt new file mode 100644 index 0000000..42c55bf --- /dev/null +++ b/docs/_sources/options/axes.rst.txt @@ -0,0 +1,163 @@ +.. _options-axes: + +Axes, coordinates, and formatting +================================= + +Control limits, units, transformations, logarithmic axes, formats, and ticks. + +.. program:: plopm + +-x/--xlim +------------------ + +.. option:: -x , --xlim + :no-contents-entry: + :no-typesetting: + +Set x-axis limits in the requested display order, for example ``[-100,200]`` or ``[200,-100]``. + +Separate limits for multiple plots with spaces: + +.. code-block:: console + + plopm -x "[-100,200] [500,0]" + +**Default:** empty + +-y/--ylim +------------------ + +.. option:: -y , --ylim + :no-contents-entry: + :no-typesetting: + +Set y-axis limits in the requested display order, for example ``[0,70]`` or ``[70,0]``. + +Separate limits for multiple plots with spaces: + +.. code-block:: console + + plopm -y "[0,10000] [0,23000]" + +**Default:** empty + +-xu/--xunits +-------------------- + +.. option:: -xu , --xunits + :no-contents-entry: + :no-typesetting: + +Set spatial-map x-axis units to ``mm``, ``cm``, ``m``, or ``km``. + +**Default:** ``m`` + +-yu/--yunits +-------------------- + +.. option:: -yu , --yunits + :no-contents-entry: + :no-typesetting: + +Set spatial-map y-axis units to ``mm``, ``cm``, ``m``, or ``km``. + +**Default:** ``m`` + +-asp/--equal-aspect <0|1> +------------------------- + +.. option:: -asp <0|1>, --equal-aspect <0|1> + :no-contents-entry: + :no-typesetting: + +Scale the axes equally in two-dimensional maps when set to ``1``. + +**Default:** ``1`` + +-rot/--rotation +------------------------- + +.. option:: -rot , --rotation + :no-contents-entry: + :no-typesetting: + +Set the grid rotation angle in degrees for two-dimensional maps. + +**Default:** ``0`` + +-tr/--translation +----------------------- + +.. option:: -tr , --translation + :no-contents-entry: + :no-typesetting: + +Set grid translation in the x and y directions, for example ``[100,-50]``. + +**Default:** ``[0,0]`` + +-xlog/--xlog <0|1> +------------------ + +.. option:: -xlog <0|1>, --xlog <0|1> + :no-contents-entry: + :no-typesetting: + +Enable a logarithmic x-axis with ``1``. Comma-separated settings are accepted when plots require different values. + +**Default:** ``0`` + +-ylog/--ylog <0|1> +------------------ + +.. option:: -ylog <0|1>, --ylog <0|1> + :no-contents-entry: + :no-typesetting: + +Enable a logarithmic y-axis with ``1``. Comma-separated settings are accepted when plots require different values. + +**Default:** ``0`` + +-xf/--xformat +---------------------- + +.. option:: -xf , --xformat + :no-contents-entry: + :no-typesetting: + +Set the x-axis number format, for example ``.2e``. + +**Default:** empty, so **plopm** selects the format. + +-yf/--yformat +---------------------- + +.. option:: -yf , --yformat + :no-contents-entry: + :no-typesetting: + +Set the y-axis number format, for example ``.1f``. + +**Default:** empty, so **plopm** selects the format. + +-xnt/--xtick-count +-------------------------- + +.. option:: -xnt , --xtick-count + :no-contents-entry: + :no-typesetting: + +Set the number of x-axis ticks. + +**Default:** ``5`` + +-ynt/--ytick-count +-------------------------- + +.. option:: -ynt , --ytick-count + :no-contents-entry: + :no-typesetting: + +Set the number of y-axis ticks. + +**Default:** ``5`` diff --git a/docs/_sources/options/computation.rst.txt b/docs/_sources/options/computation.rst.txt new file mode 100644 index 0000000..985bbea --- /dev/null +++ b/docs/_sources/options/computation.rst.txt @@ -0,0 +1,77 @@ +.. _options-computation: + +Computation and data transformation +=================================== + +Aggregate, scale, compare, and transform simulation quantities. + +.. program:: plopm + +-agg/--aggregation +---------------------------- + +.. option:: -agg , --aggregation + :no-contents-entry: + :no-typesetting: + +Set aggregation or selection methods for two-dimensional slices and projections. Supported values are ``min``, ``max``, ``sum``, ``mean``, ``pvmean``, ``harmonic``, ``arithmetic``, ``first``, and ``last``. + +Separate methods for multiple variables or plots with commas: + +.. code-block:: console + + plopm -agg "first,arithmetic,max" + +By default, continuous variables are pore-volume weighted, extensive quantities are summed, indices retain discrete values, and permeabilities use directional harmonic or arithmetic averaging. + +For wells and faults, ``min`` shows cells containing at least one occurrence, while ``max`` requires all projected cells to contain one. + +**Default:** empty, so **plopm** selects the method automatically. + +See :ref:`tutorial-projections` for a guided workflow. + +-sf/--scale-factor +---------------------------- + +.. option:: -sf , --scale-factor + :no-contents-entry: + :no-typesetting: + +Multiply variable values by a scaling factor, for example ``1e-9`` to display CO2 mass in Mt. + +Separate factors for multiple variables or plots with commas, for example ``1e-5,1``. + +**Default:** ``1`` + +-di/--difference-input +------------------------------ + +.. option:: -di , --difference-input + :no-contents-entry: + :no-typesetting: + +Set the base name or full path of the input model to subtract from the primary input. + +**Default:** empty + +-sc/--stress-coefficient +-------------------------------- + +.. option:: -sc , --stress-coefficient + :no-contents-entry: + :no-typesetting: + +Set the stress coefficient used to compute pressure limits for ``limipres``, ``overpres``, and ``objepres``. + +**Default:** ``0.134`` + +-dg/--dual-grid <0|1> +--------------------- + +.. option:: -dg <0|1>, --dual-grid <0|1> + :no-contents-entry: + :no-typesetting: + +Enable dual-grid processing with ``1`` and disable it with ``0``. + +**Default:** ``0`` diff --git a/docs/_sources/options/diagnostics.rst.txt b/docs/_sources/options/diagnostics.rst.txt new file mode 100644 index 0000000..01b7e37 --- /dev/null +++ b/docs/_sources/options/diagnostics.rst.txt @@ -0,0 +1,19 @@ +.. _options-diagnostics: + +Information and diagnostics +=========================== + +Inspect the variables available for an input case. + +.. program:: plopm + +-lv/--list-variables <0|1> +-------------------------- + +.. option:: -lv <0|1>, --list-variables <0|1> + :no-contents-entry: + :no-typesetting: + +Print the available variables when set to ``1``. + +**Default:** ``0`` diff --git a/docs/_sources/options/filtering.rst.txt b/docs/_sources/options/filtering.rst.txt new file mode 100644 index 0000000..b0702e5 --- /dev/null +++ b/docs/_sources/options/filtering.rst.txt @@ -0,0 +1,69 @@ +.. _options-filtering: + +Filtering, masking, and thresholds +================================== + +Filter cells, remove values, and add a static map mask. + +.. program:: plopm + +-flt/--filters +--------------------------- + +.. option:: -flt , --filters + :no-contents-entry: + :no-typesetting: + +Set cell-selection conditions. Join conditions for one input with ``&`` and separate filters for different inputs with commas: + +.. code-block:: console + + plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5" + +Dynamic variables such as ``sgas`` require ``RPORV`` in ``RPTRST``. + +**Default:** empty + +-vmin/--min-threshold +----------------------------- + +.. option:: -vmin , --min-threshold + :no-contents-entry: + :no-typesetting: + +Remove variable values below the minimum threshold. + +**Default:** empty + +-vmax/--max-threshold +----------------------------- + +.. option:: -vmax , --max-threshold + :no-contents-entry: + :no-typesetting: + +Remove variable values above the maximum threshold. + +**Default:** empty + +-mv/--mask-variable +------------------------------ + +.. option:: -mv , --mask-variable + :no-contents-entry: + :no-typesetting: + +Use a static variable as the background of a two-dimensional map. + +**Default:** empty + +-mt/--mask-threshold +---------------------------- + +.. option:: -mt , --mask-threshold + :no-contents-entry: + :no-typesetting: + +Set the threshold applied to the variable supplied through :option:`plopm -mv`. + +**Default:** ``1e-3`` diff --git a/docs/_sources/options/gif.rst.txt b/docs/_sources/options/gif.rst.txt new file mode 100644 index 0000000..61e8370 --- /dev/null +++ b/docs/_sources/options/gif.rst.txt @@ -0,0 +1,30 @@ +.. _options-gif: + +GIF output +========== + +These options apply only when ``-m gif`` is selected. + +.. program:: plopm + +-gi/--gif-interval +--------------------------------- + +.. option:: -gi , --gif-interval + :no-contents-entry: + :no-typesetting: + +Set the GIF frame interval in milliseconds. + +**Default:** ``1000`` + +-gl/--gif-loop <0|1> +-------------------- + +.. option:: -gl <0|1>, --gif-loop <0|1> + :no-contents-entry: + :no-typesetting: + +Loop GIF animations indefinitely when set to ``1``. + +**Default:** ``0`` diff --git a/docs/_sources/options/input-data.rst.txt b/docs/_sources/options/input-data.rst.txt new file mode 100644 index 0000000..b9abc0a --- /dev/null +++ b/docs/_sources/options/input-data.rst.txt @@ -0,0 +1,75 @@ +.. _options-input-data: + +Input and data selection +======================== + +Select simulation inputs, variables, restart steps, CSV columns, and the Flow executable. + +.. program:: plopm + +-i/--input +------------------ + +.. option:: -i , --input + :no-contents-entry: + :no-typesetting: + +Set the base name or full path of the input. Separate multiple inputs with spaces, for example ``SPE11B /home/user/SPE11B_TUNED``. + +**Default:** ``SPE11B`` + +-v/--variable +------------------------- + +.. option:: -v , --variable + :no-contents-entry: + :no-typesetting: + +Select the variables to plot. Separate variables with commas, for example ``pressure,sgas``. + +An empty entry can act as a placeholder when the corresponding input is configured with :option:`plopm -cc`: + +.. code-block:: console + + plopm -v ",BWPR:256,1,5" -cc "1,3;" + +Special variables include ``grid``, ``wells``, ``faults``, ``pcfact``, ``limipres``, ``overpres``, ``objepres``, ``krw``, ``krg``, ``krow``, ``krog``, ``pcow``, ``pcog``, ``pcwg``, ``gasm``, ``dism``, ``liqm``, ``vapm``, ``co2m``, ``h2om``, ``xco2l``, ``xh2ov``, ``xco2v``, ``xh2ol``, ``fwcdm``, and ``fgipm``. + +**Default:** ``poro,permx,permz,porv,fipnum,satnum`` + +-r/--restart +-------------------- + +.. option:: -r , --restart + :no-contents-entry: + :no-typesetting: + +Select restart steps. ``0`` is the initial state and ``-1`` is the last state. Separate selected steps with commas, for example ``0,2`` or ``0,3,10,20``, or use ``start:end[:step]``, for example ``1:3``, ``0:4:2``, or ``5:505:250``. + +GIF output uses all available steps when this option is omitted. + +**Default:** ``-1`` + +-cc/--csv-columns +--------------------------- + +.. option:: -cc , --csv-columns + :no-contents-entry: + :no-typesetting: + +Set CSV column indices, starting at 1. Use ``t,value`` for a time series or ``x,y,value`` for a spatial map. + +Separate specifications for different inputs with semicolons. An empty specification skips the corresponding input, for example ``;1,2,5`` or ``1,3;``. + +**Default:** empty + +-fp/--flow-path +------------------------- + +.. option:: -fp , --flow-path + :no-contents-entry: + :no-typesetting: + +Set the path or command for the Flow executable, for example ``/home/build/bin/flow``. This is used only to generate the grid for VTK output. + +**Default:** ``flow`` diff --git a/docs/_sources/options/layout.rst.txt b/docs/_sources/options/layout.rst.txt new file mode 100644 index 0000000..d6b8197 --- /dev/null +++ b/docs/_sources/options/layout.rst.txt @@ -0,0 +1,54 @@ +.. _options-layout: + +Figure and subplot layout +========================= + +Set figure dimensions, subplot layout, and the global colorbar. + +.. program:: plopm + +-fs/--figsize +---------------------------- + +.. option:: -fs , --figsize + :no-contents-entry: + :no-typesetting: + +Set the figure width and height in inches, separated by a comma, for example ``8,16``. + +**Default:** ``7,5`` + +-sg/--subplot-grid +--------------------------------- + +.. option:: -sg , --subplot-grid + :no-contents-entry: + :no-typesetting: + +Set the number of subplot rows and columns, separated by a comma, for example ``2,2`` for four subplots. + +**Default:** empty, so separate figures are created. + +-cbp/--colorbar-position +--------------------------------------------------- + +.. option:: -cbp , --colorbar-position + :no-contents-entry: + :no-typesetting: + +Set the global colorbar position and size as ``left,bottom,width,height``, for example ``0.1,0.95,0.8,0.02``. + +Use ``empty`` to remove the global colorbar. + +**Default:** ``0.2,0.01,0.6,0.02`` + +-rdl/--remove-duplicate-labels <0|1> +------------------------------------ + +.. option:: -rdl <0|1>, --remove-duplicate-labels <0|1> + :no-contents-entry: + :no-typesetting: + +Remove duplicated axis labels in subplot layouts when set to ``1``. + +**Default:** ``0`` diff --git a/docs/_sources/options/output.rst.txt b/docs/_sources/options/output.rst.txt new file mode 100644 index 0000000..318b9f5 --- /dev/null +++ b/docs/_sources/options/output.rst.txt @@ -0,0 +1,41 @@ +.. _options-output: + +Output options +============== + +Choose the output format, directory, and filename. + +.. program:: plopm + +-m/--format +-------------------- + +.. option:: -m , --format + :no-contents-entry: + :no-typesetting: + +Select the output format: ``png``, ``gif``, ``csv``, or ``vtk``. + +**Default:** ``png`` + +-o/--output-dir +--------------------------- + +.. option:: -o , --output-dir + :no-contents-entry: + :no-typesetting: + +Set the base name or full path of the output directory. + +**Default:** ``.``, the directory where **plopm** is executed. + +-fn/--filename +--------------------- + +.. option:: -fn , --filename + :no-contents-entry: + :no-typesetting: + +Set the output filename. + +**Default:** empty, so **plopm** generates the name. diff --git a/docs/_sources/options/plot-types.rst.txt b/docs/_sources/options/plot-types.rst.txt new file mode 100644 index 0000000..488568e --- /dev/null +++ b/docs/_sources/options/plot-types.rst.txt @@ -0,0 +1,65 @@ +.. _options-plot-types: + +Plot types and statistical representation +========================================= + +Create histograms, ensemble statistics, and step-style summary plots. + +.. program:: plopm + +-hist/--histogram +--------------------------------- + +.. option:: -hist , --histogram + :no-contents-entry: + :no-typesetting: + +Set histogram bins and an optional distribution, for example ``20``, ``20,norm``, or ``20,lognorm``. + +Separate specifications for multiple plots with spaces: + +.. code-block:: console + + plopm -hist "50,norm 20,lognorm 100" + +**Default:** empty, so no histogram is plotted. + +-ens/--ensemble +---------------------- + +.. option:: -ens , --ensemble + :no-contents-entry: + :no-typesetting: + +Set the ensemble plotting mode: + +* ``0`` disables ensemble plotting. +* ``1`` plots the mean and error bands. +* ``2`` plots the minimum, mean, and maximum. +* ``3`` plots both representations. + +**Default:** ``0`` + +-fb/--fill-between-style + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + - -
-
+ + + + + + + + + + + + + + + - - - -
- -
-
-
-
+ + + + + + + +
+ +
+ + + - + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/api/modules.html b/docs/api/modules.html new file mode 100644 index 0000000..b4954d3 --- /dev/null +++ b/docs/api/modules.html @@ -0,0 +1,619 @@ + + + + + + + + + + + plopm — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + + + + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.config.config.html b/docs/api/plopm.config.config.html new file mode 100644 index 0000000..52ddfce --- /dev/null +++ b/docs/api/plopm.config.config.html @@ -0,0 +1,1700 @@ + + + + + + + + + + + plopm.config.config module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.config.config module#

+

Configuration and simulation-data models shared across plopm workflows.

+

PlopmConfig stores command-line options and normalized runtime settings used to +create summary plots, spatial maps, animations, and VTK output. SimData stores +OPM file handles, grid dimensions, and cell data loaded for one simulation case.

+

Both objects are mutable because CLI values are normalized and simulation data +are populated progressively during processing.

+
+
+class PlopmConfig(gif=False, csv=False, png=False, vtk=False, equal_aspect=False, remove_duplicate_labels=False, list_variables=False, gif_loop=False, step_plot=False, global_range=False, rst_range=False, sensor=False, layer=False, csv_column_summary=False, discrete=True, fontsize=0.0, mask_threshold=0.0, gif_interval=0.0, stress_coefficient=0.0, xscale=1.0, yscale=1.0, ensemble=0, ncolors=1, color_log_ticks=<factory>, case_labels=<factory>, cases=<factory>, dual_grid=<factory>, subplot_grid=<factory>, variables=<factory>, filters=<factory>, title=<factory>, clim=<factory>, figsize=<factory>, min_threshold=<factory>, max_threshold=<factory>, grid_edges=<factory>, colorbar_tick_count=<factory>, legend_labels=<factory>, hide_map_elements=<factory>, time_units=<factory>, scale_factor=<factory>, axis_grid=<factory>, dpi=<factory>, colorbar_ticks=<factory>, legend_location=<factory>, vtk_format=<factory>, vtk_names=<factory>, color_log=<factory>, rotation=<factory>, filename=<factory>, translation=<factory>, restart=<factory>, aggregation=<factory>, distance=<factory>, histogram=<factory>, xlabel=<factory>, xformat=<factory>, xtick_count=<factory>, xlog=<factory>, xlim=<factory>, ylabel=<factory>, yformat=<factory>, ytick_count=<factory>, ylog=<factory>, ylim=<factory>, vsum=<factory>, summary=<factory>, time=<factory>, wells=<factory>, faults=<factory>, slice=<factory>, csv_columns=<factory>, mass_vars=<factory>, summary_mass=<factory>, mass_fracs=<factory>, caprock_vars=<factory>, linewidth_values=<factory>, units=<factory>, cb_formats=<factory>, colormaps=<factory>, disc_colormaps=<factory>, linestyle=<factory>, linewidth=<factory>, colors=<factory>, colors_default=<factory>, linestyle_default=<factory>, colorbar_position=(-1.0, -1.0, -1.0, -1.0), difference_input='', colors_raw='', output_dir='', case='', fill_between_style='', colorbar_format='', fc='', inactive_color='', mask_variable='', suptitle='', colorbar_label='', slice_mode='', xunits='', yunits='', xunit='', yunit='')[source]#
+

Bases: object

+

Options and runtime settings for a plopm operation.

+

Most list fields contain one value per variable, case, or subplot after +initialization. Values read from the CLI are normalized before plotting so +downstream functions can use consistent indexing.

+
+
Attributes:
+
+
gif, csv, png, vtk

Whether GIF, CSV, PNG, or VTK output is active for the current run.

+
+
equal_aspect

Whether spatial maps use the same scale along both coordinate axes.

+
+
remove_duplicate_labels

Whether repeated axis labels are hidden in subplot layouts.

+
+
list_variables

Whether available INIT, UNRST, and summary variables are printed.

+
+
gif_loop

Whether generated GIF animations repeat after the final frame.

+
+
step_plot

Whether one-dimensional series are drawn as step plots.

+
+
global_range

Whether map limits and features are evaluated globally instead of only +within the selected slice.

+
+
rst_range

Whether PNG color limits are evaluated over the restart range.

+
+
sensor

Whether one-dimensional values are extracted at a grid-cell sensor.

+
+
layer

Whether one-dimensional values are extracted along a grid axis or layer.

+
+
csv_column_summary

Whether a one-dimensional series is read from CSV columns.

+
+
discrete

Whether the current spatial quantity uses discrete color categories.

+
+
fontsize

Base font size used in generated figures.

+
+
mask_threshold

Threshold applied to the selected mask variable.

+
+
gif_interval

Delay between GIF frames.

+
+
stress_coefficient

Vertical stress coefficient used for caprock-integrity quantities.

+
+
xscale, yscale

Factors converting grid coordinates to the requested spatial units.

+
+
ensemble

Ensemble mode controlling uncertainty bands and bounding members.

+
+
ncolors

Number of case-dependent styles used for summary plots.

+
+
color_log_ticks

Tick values used on logarithmic colorbars.

+
+
case_labels

User-provided case names used in legends and ensemble labels.

+
+
cases

Simulation-case paths grouped as requested by the CLI.

+
+
dual_grid

Per-variable flags enabling dual-porosity grid handling.

+
+
subplot_grid

Requested subplot rows and columns.

+
+
variables

Variables or variable expressions requested for processing.

+
+
filters

Property-filter expressions applied per case or variable.

+
+
title

Per-plot titles.

+
+
clim

Lower and upper color limits for spatial maps.

+
+
figsize

Figure width and height for each generated plot.

+
+
min_threshold, max_threshold

Limits outside which quantity values are hidden.

+
+
grid_edges

Per-map settings controlling cell-edge drawing.

+
+
colorbar_tick_count

Requested number of colorbar ticks.

+
+
legend_labels

Labels for cases, variables, or ensemble bounds.

+
+
hide_map_elements

Map components to omit, such as axes, labels, or colorbars.

+
+
time_units

Requested time unit for each one-dimensional plot.

+
+
scale_factor

Multipliers applied to plotted or exported quantity values.

+
+
axis_grid

Per-plot settings controlling the Matplotlib axis grid.

+
+
dpi

Output resolution for each generated figure.

+
+
colorbar_ticks

Explicit colorbar tick values.

+
+
legend_location

Per-plot legend placement.

+
+
vtk_format

VTK data type selected for each exported variable.

+
+
vtk_names

Variable names written to VTK cell-data arrays.

+
+
color_log

Flags selecting logarithmic color normalization.

+
+
rotation

Rotation angles applied to grid coordinates, in degrees.

+
+
filename

Output filenames normalized per requested plot.

+
+
translation

Coordinate translations applied after rotation.

+
+
restart

Selected OPM restart report steps.

+
+
aggregation

Aggregation method applied through a slice or selected cells.

+
+
distance

Distance method and target, such as a sensor or model boundaries.

+
+
histogram

Histogram settings, including the requested bins.

+
+
xlabel, ylabel

Per-plot axis labels.

+
+
xformat, yformat

Format strings used for axis tick labels.

+
+
xtick_count, ytick_count

Requested numbers of major ticks.

+
+
xlog, ylog

Flags selecting logarithmic axes.

+
+
xlim, ylim

Per-plot axis limits.

+
+
vsum

Summary-variable expressions prepared for plotting.

+
+
summary

Loaded or derived summary-series values.

+
+
time

Time coordinates associated with summary values.

+
+
wells, faults

Parsed feature locations used in spatial maps.

+
+
slice

Parsed i, j, and k selections used by all workflows.

+
+
csv_columns

CSV column settings retained in parsed per-plot form.

+
+
mass_vars

Supported component-mass quantities.

+
+
summary_mass

Summary vectors converted from standard volume to mass.

+
+
mass_fracs

Supported component mass-fraction quantities.

+
+
caprock_vars

Supported caprock-integrity quantities.

+
+
linewidth_values

Default line widths before per-variable normalization.

+
+
units

Display units associated with requested quantities.

+
+
cb_formats

Normalized numeric formats used for colorbar labels.

+
+
colormaps

Colormaps assigned to spatial variables.

+
+
disc_colormaps

Available colormaps suitable for discrete values.

+
+
linestyle, linewidth, colors

Normalized styles used by summary plots.

+
+
colors_default, linestyle_default

Default style sequences used when none are supplied.

+
+
colorbar_position

Relative position and size of an explicitly placed colorbar axis.

+
+
difference_input

Second case, folder, or file used to calculate differences.

+
+
colors_raw

Color specification received from the CLI before normalization.

+
+
output_dir

Directory in which generated files are written.

+
+
case

Primary case path used for file detection and classification.

+
+
fill_between_style

Colors and opacity values for ensemble uncertainty bands.

+
+
colorbar_format

Colorbar format specification received from the CLI.

+
+
fc

Figure or axes face color.

+
+
inactive_color

Color assigned to inactive grid cells.

+
+
mask_variable

Variable used to mask spatial-map values.

+
+
suptitle

Figure-level title shared by all subplots.

+
+
colorbar_label

User-provided colorbar label.

+
+
slice_mode

Mode used when retaining wells or faults in an aggregated slice.

+
+
xunits, yunits

Requested spatial unit codes for both coordinate axes.

+
+
xunit, yunit

Formatted spatial unit labels shown on the axes.

+
+
slices

Normalized half-open ranges used for spatial slice aggregation.

+
+
csv_cols

Normalized CSV column indices used for gridded CSV data.

+
+
+
+
Parameters:
+
+
+
+
+
+gif: bool#
+
+ +
+
+csv: bool#
+
+ +
+
+png: bool#
+
+ +
+
+vtk: bool#
+
+ +
+
+equal_aspect: bool#
+
+ +
+
+remove_duplicate_labels: bool#
+
+ +
+
+list_variables: bool#
+
+ +
+
+gif_loop: bool#
+
+ +
+
+step_plot: bool#
+
+ +
+
+global_range: bool#
+
+ +
+
+rst_range: bool#
+
+ +
+
+sensor: bool#
+
+ +
+
+layer: bool#
+
+ +
+
+csv_column_summary: bool#
+
+ +
+
+discrete: bool#
+
+ +
+
+fontsize: float#
+
+ +
+
+mask_threshold: float#
+
+ +
+
+gif_interval: float#
+
+ +
+
+stress_coefficient: float#
+
+ +
+
+xscale: float#
+
+ +
+
+yscale: float#
+
+ +
+
+ensemble: int#
+
+ +
+
+ncolors: int#
+
+ +
+
+color_log_ticks: list#
+
+ +
+
+case_labels: list#
+
+ +
+
+cases: list#
+
+ +
+
+dual_grid: list#
+
+ +
+
+subplot_grid: list#
+
+ +
+
+variables: list#
+
+ +
+
+filters: list#
+
+ +
+
+title: list#
+
+ +
+
+clim: list#
+
+ +
+
+figsize: list#
+
+ +
+
+min_threshold: list#
+
+ +
+
+max_threshold: list#
+
+ +
+
+grid_edges: list#
+
+ +
+
+colorbar_tick_count: list#
+
+ +
+
+legend_labels: list#
+
+ +
+
+hide_map_elements: list#
+
+ +
+
+time_units: list#
+
+ +
+
+scale_factor: list#
+
+ +
+
+axis_grid: list#
+
+ +
+
+dpi: list#
+
+ +
+
+colorbar_ticks: list#
+
+ +
+
+legend_location: list#
+
+ +
+
+vtk_format: list#
+
+ +
+
+vtk_names: list#
+
+ +
+
+color_log: list#
+
+ +
+
+rotation: list#
+
+ +
+
+filename: list#
+
+ +
+
+translation: list#
+
+ +
+
+restart: list#
+
+ +
+
+aggregation: list#
+
+ +
+
+distance: list#
+
+ +
+
+histogram: list#
+
+ +
+
+xlabel: list#
+
+ +
+
+xformat: list#
+
+ +
+
+xtick_count: list#
+
+ +
+
+xlog: list#
+
+ +
+
+xlim: list#
+
+ +
+
+ylabel: list#
+
+ +
+
+yformat: list#
+
+ +
+
+ytick_count: list#
+
+ +
+
+ylog: list#
+
+ +
+
+ylim: list#
+
+ +
+
+vsum: list#
+
+ +
+
+summary: list#
+
+ +
+
+time: list#
+
+ +
+
+wells: list#
+
+ +
+
+faults: list#
+
+ +
+
+slice: list#
+
+ +
+
+csv_columns: list#
+
+ +
+
+mass_vars: list#
+
+ +
+
+summary_mass: list#
+
+ +
+
+mass_fracs: list#
+
+ +
+
+caprock_vars: list#
+
+ +
+
+linewidth_values: list#
+
+ +
+
+units: list#
+
+ +
+
+cb_formats: list#
+
+ +
+
+colormaps: list#
+
+ +
+
+disc_colormaps: list#
+
+ +
+
+linestyle: list#
+
+ +
+
+linewidth: list#
+
+ +
+
+colors: list#
+
+ +
+
+colors_default: list#
+
+ +
+
+linestyle_default: list#
+
+ +
+
+colorbar_position: tuple[float, float, float, float]#
+
+ +
+
+difference_input: str#
+
+ +
+
+colors_raw: str#
+
+ +
+
+output_dir: str#
+
+ +
+
+case: str#
+
+ +
+
+fill_between_style: str#
+
+ +
+
+colorbar_format: str#
+
+ +
+
+fc: str#
+
+ +
+
+inactive_color: str#
+
+ +
+
+mask_variable: str#
+
+ +
+
+suptitle: str#
+
+ +
+
+colorbar_label: str#
+
+ +
+
+slice_mode: str#
+
+ +
+
+xunits: str#
+
+ +
+
+yunits: str#
+
+ +
+
+xunit: str#
+
+ +
+
+yunit: str#
+
+ +
+ +
+
+class SimData(init=None, unrst=None, grid=None, porv=<factory>, dx=<factory>, dy=<factory>, dz=<factory>, active_pv=<factory>, active_idx=<factory>, steps=<factory>, times=<factory>, ncells=0, nsteps=0, nx=0, ny=0, nz=0)[source]#
+

Bases: object

+

OPM readers, grid properties, and selected report steps for one case.

+

Arrays in global cell order use the full nx * ny * nz grid. Arrays in +active-cell order follow the indexing used by INIT and UNRST properties.

+
+
Attributes:
+
+
init, unrst, grid

OPM readers for static properties, restart properties, and grid geometry.

+
+
porv

Pore volume in global cell order; inactive cells are non-positive.

+
+
dx, dy, dz

Cell dimensions in active-cell order.

+
+
active_pv

Pore volume in active-cell order.

+
+
active_idx

Mapping from global cell indices to active-cell indices.

+
+
steps, times

Selected restart report steps and their simulation times.

+
+
ncells, nsteps

Total grid-cell and available report-step counts.

+
+
nx, ny, nz

Grid dimensions along the i, j, and k axes.

+
+
+
+
Parameters:
+
    +
  • init (EclFile)

  • +
  • unrst (ERst)

  • +
  • grid (EGrid)

  • +
  • porv (NDArray)

  • +
  • dx (NDArray)

  • +
  • dy (NDArray)

  • +
  • dz (NDArray)

  • +
  • active_pv (NDArray)

  • +
  • active_idx (NDArray)

  • +
  • steps (list)

  • +
  • times (list)

  • +
  • ncells (int)

  • +
  • nsteps (int)

  • +
  • nx (int)

  • +
  • ny (int)

  • +
  • nz (int)

  • +
+
+
+
+
+init: EclFile#
+
+ +
+
+unrst: ERst#
+
+ +
+
+grid: EGrid#
+
+ +
+
+porv: NDArray#
+
+ +
+
+dx: NDArray#
+
+ +
+
+dy: NDArray#
+
+ +
+
+dz: NDArray#
+
+ +
+
+active_pv: NDArray#
+
+ +
+
+active_idx: NDArray#
+
+ +
+
+steps: list#
+
+ +
+
+times: list#
+
+ +
+
+ncells: int#
+
+ +
+
+nsteps: int#
+
+ +
+
+nx: int#
+
+ +
+
+ny: int#
+
+ +
+
+nz: int#
+
+ +
+ +
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.config.html b/docs/api/plopm.config.html new file mode 100644 index 0000000..b3e7e4a --- /dev/null +++ b/docs/api/plopm.config.html @@ -0,0 +1,759 @@ + + + + + + + + + + + plopm.config package — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.config package#

+
+

Submodules#

+ +
+
+

Module contents#

+

Code version

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.core.html b/docs/api/plopm.core.html new file mode 100644 index 0000000..a203806 --- /dev/null +++ b/docs/api/plopm.core.html @@ -0,0 +1,634 @@ + + + + + + + + + + + plopm.core package — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + + + + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.core.plopm.html b/docs/api/plopm.core.plopm.html new file mode 100644 index 0000000..5424461 --- /dev/null +++ b/docs/api/plopm.core.plopm.html @@ -0,0 +1,661 @@ + + + + + + + + + + + plopm.core.plopm module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.core.plopm module#

+

Command-line entry point and top-level workflow coordination for plopm.

+

plopm supports three output workflows for OPM Flow simulation results:

+
    +
  • One-dimensional plots and CSV files can be generated from summary vectors, +tabulated functions, grid-cell sensors, layers, histograms, and distances.

  • +
  • Two-dimensional PNG figures and GIF animations can be generated for selected +grid slices, with optional aggregation, masking, differences, wells, and faults.

  • +
  • VTK time series can be generated by combining OPM grid geometry with selected +INIT and UNRST properties.

  • +
+

This module parses and validates command-line arguments, builds the runtime +configuration, selects the appropriate workflow, and reports the generated +files. Data reading, numerical processing, plotting, and file generation are +implemented in the utility modules.

+
+
+main(argv=None)[source]#
+

Run the plopm command-line workflow.

+

The function parses and validates CLI arguments, builds the shared +configuration, and dispatches VTK export, one-dimensional plotting, or +two-dimensional map generation. It reports the generated files after the +selected workflow completes.

+
+
Parameters:
+
+
argvlist[str], optional

Arguments to parse instead of sys.argv[1:]. This is primarily used +by tests and programmatic callers.

+
+
+
+
Parameters:
+

argv (list[str] | None)

+
+
Return type:
+

None

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.html b/docs/api/plopm.html new file mode 100644 index 0000000..b9e8f2c --- /dev/null +++ b/docs/api/plopm.html @@ -0,0 +1,715 @@ + + + + + + + + + + + plopm package — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm package#

+
+

Subpackages#

+ +
+
+

Module contents#

+

Code version

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.html b/docs/api/plopm.utils.html new file mode 100644 index 0000000..feaf4ec --- /dev/null +++ b/docs/api/plopm.utils.html @@ -0,0 +1,696 @@ + + + + + + + + + + + plopm.utils package — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + + +
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.initialization.html b/docs/api/plopm.utils.initialization.html new file mode 100644 index 0000000..cfba36f --- /dev/null +++ b/docs/api/plopm.utils.initialization.html @@ -0,0 +1,788 @@ + + + + + + + + + + + plopm.utils.initialization module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.initialization module#

+

Build and normalize configuration for plopm workflows.

+

The module converts parsed CLI arguments into PlopmConfig, discovers +simulation cases, normalizes per-variable plotting settings, selects summary or +spatial processing, and defines unit conversions used by the readers.

+
+
+build_config(cmdargs)[source]#
+

Build a plopm configuration from parsed CLI arguments.

+

The function expands case and difference-input paths, parses list-like +options, normalizes slice and restart selections, and initializes plotting +defaults shared by summary, map, and VTK workflows.

+
+
Parameters:
+
+
cmdargsargparse.Namespace

Command-line arguments returned by the plopm parser.

+
+
+
+
Returns:
+
+
PlopmConfig

Parsed and partially normalized runtime configuration.

+
+
+
+
Parameters:
+

cmdargs (Namespace)

+
+
Return type:
+

PlopmConfig

+
+
+
+ +
+
+init_maps(cfg)[source]#
+

Normalize settings used by spatial maps.

+

The function selects default units, colorbar formats, and colormaps; expands +per-variable limits and formats; and initializes spatial coordinate scales.

+
+
Parameters:
+
+
cfgPlopmConfig

Configuration updated in place for map generation.

+
+
+
+
Parameters:
+

cfg (PlopmConfig)

+
+
Return type:
+

None

+
+
+
+ +
+
+spatial_unit(unit)[source]#
+

Get the conversion and label for a spatial unit.

+
+
Parameters:
+
+
unitstr

Spatial-unit code.

+
+
+
+
Returns:
+
+
tuple[float, str]

Factor converting metres and the formatted unit label.

+
+
+
+
Parameters:
+

unit (str)

+
+
Return type:
+

tuple[float, str]

+
+
+
+ +
+
+mass_unit(mskl)[source]#
+

Get the display unit for a mass scale factor.

+
+
Parameters:
+
+
msklfloat

Factor applied to quantities stored in kilograms.

+
+
+
+
Returns:
+
+
str

Matplotlib-formatted mass unit, or an empty string when unknown.

+
+
+
+
Parameters:
+

mskl (float)

+
+
Return type:
+

str

+
+
+
+ +
+
+is_summary(cfg)[source]#
+

Determine whether the request uses one-dimensional output.

+

The decision considers explicit series options, special tabulated +properties, summary-vector availability, and requests to list variables.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized configuration and primary case path.

+
+
+
+
Returns:
+
+
bool

True when the request should use the summary plotting workflow.

+
+
+
+
Parameters:
+

cfg (PlopmConfig)

+
+
Return type:
+

bool

+
+
+
+ +
+
+init_summary(cfg)[source]#
+

Normalize settings used by one-dimensional plots.

+
+
Parameters:
+
+
cfgPlopmConfig

Configuration updated in place with per-variable styles and labels.

+
+
+
+
Parameters:
+

cfg (PlopmConfig)

+
+
Return type:
+

None

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.mapping.html b/docs/api/plopm.utils.mapping.html new file mode 100644 index 0000000..48c4194 --- /dev/null +++ b/docs/api/plopm.utils.mapping.html @@ -0,0 +1,937 @@ + + + + + + + + + + + plopm.utils.mapping module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.mapping module#

+

Prepare slice geometry and map three-dimensional values to two dimensions.

+

The module builds labels and coordinate meshes for xy, xz, and yz slices, +applies optional rotation and translation, and aggregates active-cell values +through the selected grid interval.

+
+
+get_yz_slice(cfg, data, n)[source]#
+

Prepare geometry and labels for a yz slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map and slice configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple

Coordinate meshes, display and filename slice labels, mapped grid +dimensions, and coordinate-axis names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray, str, str, int, int, str, str]

+
+
+
+ +
+
+get_xz_slice(cfg, data, n)[source]#
+

Prepare geometry and labels for an xz slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map and slice configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple

Coordinate meshes, display and filename slice labels, mapped grid +dimensions, and coordinate-axis names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray, str, str, int, int, str, str]

+
+
+
+ +
+
+get_xy_slice(cfg, data, n)[source]#
+

Prepare geometry and labels for an xy slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map and slice configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple

Coordinate meshes, display and filename slice labels, mapped grid +dimensions, and coordinate-axis names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray, str, str, int, int, str, str]

+
+
+
+ +
+
+transform_grid(cfg, n, xc, yc)[source]#
+

Rotate and translate a two-dimensional coordinate mesh.

+
+
Parameters:
+
+
cfgPlopmConfig

Rotation and translation settings.

+
+
nint

Map index.

+
+
xc, ycnp.ndarray

Coordinate meshes to transform.

+
+
+
+
Returns:
+
+
tuple[np.ndarray, np.ndarray]

Transformed x- and y-coordinate meshes.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray]

+
+
+
+ +
+
+map_xz(cfg, data, var, values, n, mx, my, features=None, feature_id=1)[source]#
+

Aggregate active-cell values onto an xz slice.

+

Values are aggregated through the selected j interval. Permeability uses +arithmetic or harmonic thickness weighting according to flow direction; +other properties use the configured aggregation or pore-volume weighting.

+
+
Parameters:
+
+
cfgPlopmConfig

Slice and aggregation configuration.

+
+
dataSimData

Loaded grid properties and active-cell mapping.

+
+
varstr

Variable name.

+
+
valuesnp.ndarray

Values in active-cell order.

+
+
nint

Map index.

+
+
mx, myint

Mapped grid dimensions.

+
+
featureslist, optional

Wells or faults grouped by label.

+
+
feature_idint, default: 1

Category assigned when mapping one feature.

+
+
+
+
Returns:
+
+
np.ndarray

Values on the flattened xz plotting grid.

+
+
+
+
Parameters:
+
+
+
Return type:
+

NDArray

+
+
+
+ +
+
+map_yz(cfg, data, var, values, n, mx, my, features=None, feature_id=1)[source]#
+

Aggregate active-cell values onto a yz slice.

+

Values are aggregated through the selected i interval. Permeability uses +arithmetic or harmonic thickness weighting according to flow direction; +other properties use the configured aggregation or pore-volume weighting.

+
+
Parameters:
+
+
cfgPlopmConfig

Slice and aggregation configuration.

+
+
dataSimData

Loaded grid properties and active-cell mapping.

+
+
varstr

Variable name.

+
+
valuesnp.ndarray

Values in active-cell order.

+
+
nint

Map index.

+
+
mx, myint

Mapped grid dimensions.

+
+
featureslist, optional

Wells or faults grouped by label.

+
+
feature_idint, default: 1

Category assigned when mapping one feature.

+
+
+
+
Returns:
+
+
np.ndarray

Values on the flattened yz plotting grid.

+
+
+
+
Parameters:
+
+
+
Return type:
+

NDArray

+
+
+
+ +
+
+map_xy(cfg, data, var, values, n, mx, my, features=None, feature_id=1)[source]#
+

Aggregate active-cell values onto an xy slice.

+

Values are aggregated through the selected k interval. Dual-porosity rows +are included when enabled, and permeability is weighted according to the +vertical flow direction.

+
+
Parameters:
+
+
cfgPlopmConfig

Slice, aggregation, and dual-grid configuration.

+
+
dataSimData

Loaded grid properties and active-cell mapping.

+
+
varstr

Variable name.

+
+
valuesnp.ndarray

Values in active-cell order.

+
+
nint

Map index.

+
+
mx, myint

Mapped grid dimensions.

+
+
featureslist, optional

Wells or faults grouped by label.

+
+
feature_idint, default: 1

Category assigned when mapping one feature.

+
+
+
+
Returns:
+
+
np.ndarray

Values on the flattened xy plotting grid.

+
+
+
+
Parameters:
+
+
+
Return type:
+

NDArray

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.readers.html b/docs/api/plopm.utils.readers.html new file mode 100644 index 0000000..a2dc90a --- /dev/null +++ b/docs/api/plopm.utils.readers.html @@ -0,0 +1,1040 @@ + + + + + + + + + + + plopm.utils.readers module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.readers module#

+

Read and derive plotting quantities from OPM Flow output.

+

The module opens INIT, UNRST, EGRID, SMSPEC, deck, and CSV data; constructs +plotting coordinates; evaluates variable expressions; and derives saturation, +mass, caprock, distance, well, and fault quantities.

+
+
+read_case(deck, gif, vtk, variables, restart, filters, n=0)[source]#
+

Open the OPM output required for one simulation case.

+
+
Parameters:
+
+
deckstr

Simulation-case stem without an extension.

+
+
gif, vtkbool

Output modes controlling restart and grid loading.

+
+
variableslist

Requested variables or expressions.

+
+
restartlist

Requested restart report steps.

+
+
filterslist

Property-filter expressions.

+
+
nint, default: 0

Case index used to select per-case settings.

+
+
+
+
Returns:
+
+
SimData

Loaded readers, grid properties, and report-step metadata.

+
+
+
+
Parameters:
+
+
+
Return type:
+

SimData

+
+
+
+ +
+
+get_yz_coords(cfg, data, n)[source]#
+

Build coordinate meshes for a yz slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple[np.ndarray, np.ndarray]

Y- and z-coordinate meshes.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray]

+
+
+
+ +
+
+get_xz_coords(cfg, data, n)[source]#
+

Build coordinate meshes for an xz slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple[np.ndarray, np.ndarray]

X- and z-coordinate meshes.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray]

+
+
+
+ +
+
+get_xy_coords(cfg, data, n)[source]#
+

Build coordinate meshes for an xy slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map configuration.

+
+
dataSimData

Loaded grid data.

+
+
nint

Slice index.

+
+
+
+
Returns:
+
+
tuple[np.ndarray, np.ndarray]

X- and y-coordinate meshes.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray]

+
+
+
+ +
+
+read_series(cfg, case, values, tunit, qskl, n)[source]#
+

Read one one-dimensional series for plotting.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized series configuration.

+
+
casestr

Simulation-case stem or CSV path.

+
+
valuesstr

Variable name or expression.

+
+
tunitstr

Requested time-unit code.

+
+
qsklfloat

Scale factor applied to values.

+
+
nint

Plot or case index.

+
+
+
+
Returns:
+
+
tuple[np.ndarray, np.ndarray, str, str]

Coordinates, values, coordinate unit, and value unit.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray, str, str]

+
+
+
+ +
+
+time_unit(times)[source]#
+

Get the conversion and label for a time unit.

+
+
Parameters:
+
+
timesstr

Time-unit code or "dates".

+
+
+
+
Returns:
+
+
tuple[float, str]

Factor converting OPM days and the axis label.

+
+
+
+
Parameters:
+

times (str)

+
+
Return type:
+

tuple[float, str]

+
+
+
+ +
+
+read_csv_grid(cfg, deck, n)[source]#
+

Read coordinate meshes from a regular CSV grid.

+
+
Parameters:
+
+
cfgPlopmConfig

CSV column and animation configuration.

+
+
deckstr

CSV path without the extension.

+
+
nint

Map index.

+
+
+
+
Returns:
+
+
tuple

Coordinate meshes, dimensions, and axis names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[NDArray, NDArray, int, int, str, str]

+
+
+
+ +
+
+get_unit(name)[source]#
+

Get the display unit for a variable.

+
+
Parameters:
+
+
namestr

Variable name.

+
+
+
+
Returns:
+
+
str

Matplotlib-formatted unit label.

+
+
+
+
Parameters:
+

name (str)

+
+
Return type:
+

str

+
+
+
+ +
+
+read_quantity(deck, data, name, step, scale, mass, mass_all, caprock, stress, filters, isgif, vmin, vmax, cvs)[source]#
+

Read and transform one spatial or VTK quantity.

+
+
Parameters:
+
+
deckstr

Simulation-case stem or CSV path.

+
+
dataSimData

Loaded simulation data.

+
+
namestr

Variable name or expression.

+
+
stepint

Restart report step.

+
+
scalefloat

Scale factor applied to derived values.

+
+
mass, mass_all, caprocklist[str]

Supported derived-variable groups.

+
+
stressfloat

Stress coefficient for caprock quantities.

+
+
filtersstr

Property-filter expression.

+
+
isgifbool

Whether the CSV path contains a restart placeholder.

+
+
vmin, vmaxstr

Optional value thresholds.

+
+
cvslist

CSV input and column settings.

+
+
+
+
Returns:
+
+
tuple[str, np.ndarray]

Unit label and quantity values.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[str, NDArray]

+
+
+
+ +
+
+get_wells(cfg, n)[source]#
+

Read wells intersecting the selected slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Case and slice configuration.

+
+
nint

Case index.

+
+
+
+
Returns:
+
+
tuple[list, list[str]]

Completion intervals grouped by well and the well names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[list, list]

+
+
+
+ +
+
+get_faults(cfg, n)[source]#
+

Read faults intersecting the selected slice.

+
+
Parameters:
+
+
cfgPlopmConfig

Case and slice configuration.

+
+
nint

Case index.

+
+
+
+
Returns:
+
+
tuple[list, list[str]]

Grid segments grouped by fault and the fault names.

+
+
+
+
Parameters:
+
+
+
Return type:
+

tuple[list, list]

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.terminal.html b/docs/api/plopm.utils.terminal.html new file mode 100644 index 0000000..4249312 --- /dev/null +++ b/docs/api/plopm.utils.terminal.html @@ -0,0 +1,939 @@ + + + + + + + + + + + plopm.utils.terminal module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.terminal module#

+

Format plopm help text and command-line messages.

+

The module hides deprecated aliases from --help, reports their replacements, +and applies ANSI colors only when supported by the selected output stream.

+
+
+class PlopmHelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, color=True)[source]#
+

Bases: ArgumentDefaultsHelpFormatter

+

Argparse formatter that hides deprecated option aliases.

+

Current options retain the standard +argparse.ArgumentDefaultsHelpFormatter layout and default values.

+

Methods

+
+ + + + + + + + + + + + + + + + + + + + + + + +

add_argument

add_arguments

add_text

add_usage

end_section

format_help

start_section

+
+
+ +
+
+warn_deprecated_options(argv)[source]#
+

Warn once for each deprecated option in an argument list.

+
+
Parameters:
+
+
argvSequence[str]

Command-line arguments, excluding or including the executable name.

+
+
+
+
Parameters:
+

argv (Sequence[str])

+
+
Return type:
+

None

+
+
+
+ +
+
+cli_deprecated_value(value)[source]#
+

Format a deprecated CLI option or value.

+
+
Parameters:
+
+
valuestr

Option or value to display.

+
+
+
+
Returns:
+
+
str

Quoted value with deprecated-option styling when supported.

+
+
+
+
Parameters:
+

value (str)

+
+
Return type:
+

str

+
+
+
+ +
+
+cli_current_value(value)[source]#
+

Format a current CLI option or value.

+
+
Parameters:
+
+
valuestr

Option or value to display.

+
+
+
+
Returns:
+
+
str

Quoted value with current-option styling when supported.

+
+
+
+
Parameters:
+

value (str)

+
+
Return type:
+

str

+
+
+
+ +
+
+cli_error_value(value)[source]#
+

Format an invalid CLI option or value.

+
+
Parameters:
+
+
valuestr

Option or value to display.

+
+
+
+
Returns:
+
+
str

Quoted value with error styling when supported.

+
+
+
+
Parameters:
+

value (str)

+
+
Return type:
+

str

+
+
+
+ +
+
+cli_info_value(value)[source]#
+

Format an informational CLI option or value.

+
+
Parameters:
+
+
valuestr

Option or value to display.

+
+
+
+
Returns:
+
+
str

Quoted value with informational styling when supported.

+
+
+
+
Parameters:
+

value (str)

+
+
Return type:
+

str

+
+
+
+ +
+
+plopm_error(message)[source]#
+

Raise a fatal command-line error.

+
+
Parameters:
+
+
messagestr

Error message displayed after the plopm label.

+
+
+
+
Raises:
+
+
SystemExit

Always raised with the formatted error message.

+
+
+
+
Parameters:
+

message (str)

+
+
Return type:
+

NoReturn

+
+
+
+ +
+
+plopm_warning(message)[source]#
+

Display a non-fatal command-line warning.

+
+
Parameters:
+
+
messagestr

Warning message displayed on standard error.

+
+
+
+
Parameters:
+

message (str)

+
+
Return type:
+

None

+
+
+
+ +
+
+plopm_info(message)[source]#
+

Display an informational command-line message.

+
+
Parameters:
+
+
messagestr

Message displayed on standard output.

+
+
+
+
Parameters:
+

message (str)

+
+
Return type:
+

None

+
+
+
+ +
+
+plopm_tip(message)[source]#
+

Display a command-line suggestion.

+
+
Parameters:
+
+
messagestr

Suggestion displayed on standard output.

+
+
+
+
Parameters:
+

message (str)

+
+
Return type:
+

None

+
+
+
+ +
+
+plopm_success(output_dir, filenames)[source]#
+

Display the generated output location and filenames.

+
+
Parameters:
+
+
output_dirstr

Directory containing the generated files.

+
+
filenameslist[str]

Generated filenames.

+
+
+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+plopm_name(stream=<_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>)[source]#
+

Format the plopm program name.

+
+
Parameters:
+
+
streamobject, default: sys.stderr

Output stream used to determine color support.

+
+
+
+
Returns:
+
+
str

Program name with gradient colors when supported.

+
+
+
+
Parameters:
+

stream (object)

+
+
Return type:
+

str

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.write_oned.html b/docs/api/plopm.utils.write_oned.html new file mode 100644 index 0000000..5f69dda --- /dev/null +++ b/docs/api/plopm.utils.write_oned.html @@ -0,0 +1,657 @@ + + + + + + + + + + + plopm.utils.write_oned module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.write_oned module#

+

Create one-dimensional plots and tabular output from OPM results.

+

The module reads summary vectors, grid-derived series, and optional CSV data. +It also supports ensemble statistics, subplot layouts, and PNG or CSV output.

+
+
+make_plots(cfg)[source]#
+

Create the requested one-dimensional plots and CSV files.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized plotting configuration.

+
+
+
+
Returns:
+
+
list[str]

Names of the generated files.

+
+
+
+
Parameters:
+

cfg (PlopmConfig)

+
+
Return type:
+

list[str]

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.write_twod.html b/docs/api/plopm.utils.write_twod.html new file mode 100644 index 0000000..00e1591 --- /dev/null +++ b/docs/api/plopm.utils.write_twod.html @@ -0,0 +1,658 @@ + + + + + + + + + + + plopm.utils.write_twod module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.write_twod module#

+

Create two-dimensional maps and animations from OPM results.

+

The module prepares grid geometry, maps three-dimensional properties onto +selected slices, and writes PNG or GIF output with optional masks, differences, +well and fault overlays, and shared color limits.

+
+
+make_maps(cfg)[source]#
+

Create the requested spatial maps and animations.

+
+
Parameters:
+
+
cfgPlopmConfig

Initialized map configuration.

+
+
+
+
Returns:
+
+
list[str]

Names of the generated PNG and GIF files.

+
+
+
+
Parameters:
+

cfg (PlopmConfig)

+
+
Return type:
+

list[str]

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api/plopm.utils.write_vtk.html b/docs/api/plopm.utils.write_vtk.html new file mode 100644 index 0000000..99dbdb2 --- /dev/null +++ b/docs/api/plopm.utils.write_vtk.html @@ -0,0 +1,707 @@ + + + + + + + + + + + plopm.utils.write_vtk module — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

plopm.utils.write_vtk module#

+

Create VTK files from OPM Flow simulation results.

+

The module runs a minimal OPM Flow job when grid geometry is unavailable, +populates VTU cell-data arrays for selected restart steps, and writes the PVD +collection used to open the resulting time series.

+
+
+make_vtks(flow, names, output, save, restart, variables, vtkformat_list, vtknames, gif, vtk, filters, scales, mass, mass_all, caprock, stress, filterss)[source]#
+

Create VTK time-series output for the configured cases.

+

A minimal OPM Flow run creates the grid-only VTU file when needed. Selected +properties are then read from INIT or UNRST output and written to one VTU +file per restart step.

+
+
Parameters:
+
+
flowstr

Command used to run OPM Flow.

+
+
nameslist

Simulation-case stems grouped by the CLI input.

+
+
outputstr

Directory in which VTK files are written.

+
+
savelist

Optional output stems for each case.

+
+
restartlist

Restart report steps to export.

+
+
variableslist

Variables or expressions written as cell data.

+
+
vtkformat_listlist

VTK data type selected for each variable.

+
+
vtknameslist

Optional VTK array names for each variable.

+
+
gif, vtkbool

Output-mode flags passed to the simulation readers.

+
+
filterslist

Property filters used while loading each case.

+
+
scaleslist[str]

Scale factor applied to each variable.

+
+
mass, mass_alllist[str]

Mass variables and all supported mass-related variables.

+
+
caprocklist[str]

Supported caprock-integrity variables.

+
+
stressfloat

Vertical stress coefficient used for caprock quantities.

+
+
filtersslist[str]

Filter expressions applied while reading exported quantities.

+
+
+
+
Returns:
+
+
list[str]

Names of the generated PVD collection files.

+
+
+
+
Parameters:
+
+
+
Return type:
+

list

+
+
+
+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/command-line.html b/docs/command-line.html new file mode 100644 index 0000000..106b922 --- /dev/null +++ b/docs/command-line.html @@ -0,0 +1,623 @@ + + + + + + + + + + + Command-line reference — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Command-line reference#

+

This section describes the plopm command syntax and all supported +command-line options.

+

Start with Syntax and conventions for input lists, variables, model slices, +restart steps, text separators, and output formats. For guided workflows, see +the Tutorial. For task-oriented commands, browse the Examples.

+ +
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/contributing.html b/docs/contributing.html index fed2c6b..22a2d24 100644 --- a/docs/contributing.html +++ b/docs/contributing.html @@ -1,96 +1,492 @@ - - - - - - - Contributing — plopm documentation - - - - - - - - - - - + + + + + + + + + Contributing — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + - -
-
+ + - - -
- -
-
-
-
+ + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ +
-
-
- +
+ + + + + +
+
-

Contributing

+

Contributing#

Contributions are more than welcome using the fork and pull request approach 🙂 (if you are not familiar with this approach, please visit GitHub Docs PRs for an extended documentation about collaborating with pull request; also, looking at previous merged pull requests helps to get familiar with this).

-

Ground Rules

+

Ground Rules#

  • We use Black code formatting

  • We use Pylint and Ruff code analysis tools

  • @@ -98,7 +494,7 @@

    Ground Rules -

    Contribute to the software

    +

    Contribute to the software#

    1. Work on your own fork of the main repo

    2. In the main repo execute:

      @@ -124,14 +520,14 @@

      Contribute to the software -

      Reporting issues or problems

      +

      Reporting issues or problems#

      1. Issues or problems can be raised by creating a new issue in the repository GitHub page (if you are not familiar with this approach, please visit GitHub Docs Issues).

      2. We will try to answer as soon as possible, but also any user is more than welcome to answer.

-

Seek support

+

Seek support#

  1. The preferred approach to seek support is to raise an Issue as described in the previous lines.

  2. We will try to answer as soon as possible, but also any user is more than welcome to answer.

  3. @@ -143,34 +539,115 @@

    Seek support - - -

+ + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+ + + - + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/examples.html b/docs/examples.html index 7eb5773..bb29c2c 100644 --- a/docs/examples.html +++ b/docs/examples.html @@ -1,582 +1,792 @@ - - - - - - - Examples — plopm documentation - - - - - - - - - - - + + + + + + + + + Examples — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + -
- - -
- -
-
-
-
    -
  • - -
  • - View page source -
  • + +
    + + +
    +
    + +
    +
    + +
    + +
    + +
    -
    -
    - + +
    + + +
    +
    + + + + + +
    +
    -

    Examples

    +

    Examples#

    +

    Select an example to view its commands, figures, and related options.

    See this presentation from the OPM summit 2025 for additional examples using plopm, as well as the one from the OPM summit 2026.

    Warning

    -

    By default the figure is generated from the front cells on the xy-plane (-s ,1,) and the axes are scaled (-asp 1), which for models with large lateral -extend could lead to a figure such as the below one:

    -
    -_images/docs_z_flag.png -
    -

    Then, you could set these flags to -s ,,1 -asp 0 when you run plopm to not scale the axes and to plot the top view of the model.

    -
    -
    -

    Tip

    -

    You can try to generate all figures from the examples below by executing inside the plopm folder:

    -
    . tests/scripts/docs_all.sh
    -
    -
    -

    See the files inside the scripts folder for the commands to be run.

    -
    -
    -

    Hello world

    -

    The simulation files located in the examples folder were generated using -pyopmspe11 by running this configuration file. -Then, if you succeed in installing plopm, inside the examples folder by typing in the terminal

    -
    plopm -i SPE11B
    -
    -
    -

    the following figure should be generated (this example is used in the tests, then it runs with the default terminal argument options).

    -
    -_images/spe11b_satnum_%2A%2C1%2C%2A_t5.png -
    -

    See the Command-line interface or run plopm -h for the definition of the argument options, as well as using -lv 1 flag to output the available -summary, init, and restart available variables given an input deck.

    -

    For example, for the gas saturation at the report step number 4 with three colorbar labels using a given colormap (-c) and defined colorbar ticks (-cbt):

    -
    plopm -i SPE11B -v sgas -r 4 -cbn 3 -c cubehelix -cbt '[0, middle, 0.9]'
    -
    -
    -
    -_images/spe11b_sgas_i%2C1%2Ck_t4.png -
    -

    and for the gas in place summary vector given a color, line style, font size, dimension of the figure, line width, and using dates for the times:

    -
    plopm -i SPE11B -v fgip -c b -ls dotted -fz 12 -fs 5,5 -lw 4 -tu dates
    -
    -
    -
    -_images/fgip.png - -
    -

    To plot cell values over time, this can be achieved by:

    -
    plopm -i 'SPE11B SPE11B SPE11B' -v 'pressure - 0pressure' -s '1,1,1 41,1,29 83,1,58' -llb 'Top left corner  Middle  Right lower corner' -yl 'Pressure increase at the sensor locations [bar]' -yf .0f -xnt 11 -tu dates
    -
    +

    The default view is -s ,1, with equal axis scaling -asp 1. For models with a +large lateral extent, use -s ,,1 -asp 0 for an unscaled top view.

    -
    -_images/spe11b_pressure-0pressure.png - -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_hello_world.sh):

    -
    . ./tests/scripts/docs_hello_world.sh
    -
    -
    -
    -
    -
    -

    Colormaps

    -

    The flag -c allows to set colormaps from Matplotlib (e.g., -c turbo), -colormaps from colorcet (e.g., -c cet_glasbey_bw), or user defined colorbars, where -each color is given in RGB (e.g., -c ‘193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130’) or HEX format (e.g., -c ‘#b6c406 #fffa86’).

    -

    Different colormap formats can be used when making a subfigure, for example:

    -
    plopm -i SPE11B -v satnum,fipnum,disperc -c '193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130',cet_glasbey_bw,'#b6c406 #fffa86' -sg 3,1 -rdl 1 -cbn 3,6,2 -cbf .0f,.0f,.1f -fs 7,4
    -
    -
    -
    -_images/spe11b_disperc_i%2C1%2Ck_t5.png - -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_colormaps.sh):

    -
    . ./tests/scripts/docs_colormaps.sh
    -
    -
    -
    -
    -
    -

    Generic deck

    -

    See/run the test_generic_deck.py -for an example where plopm is used to generate figures from the -SPE10_MODEL2 model by downloading the files and using the -OPM Flow simulator.

    -_images/spe10_model2_permz_%2A%2C4%2C%2A_t0.png -
    plopm -i SPE10_MODEL2 -v permz -s ,4, -clog 1 -xu km -yu km -xnt 6 -yf .2f -t 'K$_z$ at the forth slide in the xz plane' -cl '[1e-7,1e3]'
    -
    -
    -

    Here, we look at the forth slide in the xz plane and use log scale for the permeability in the z direction, as well as changing the axis units to km, -setting the format to the numbers to two floats in the y axis, and setting manually the upper and lower bound for the color map.

    -

    To plot information for the grid, and also the location of the wells from the top view, this is achieved by:

    -
    plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v grid -hide 0,0,1,0 && plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v wells -hide 0,0,0,1
    -
    -
    -_images/wells.png -

    Here, we use the remove flag to delete the colorbar axis in the maps for the grid and to delete the generated title in the wells plot (the first entry -in remove would delete the left axis, e.g., the y label and y ticks in this example, while the second entry if set to 1 would remove the x axis).

    -
    -

    Tip

    -

    All previous commands can be executed as (docs_generic_deck.sh):

    -
    . ./tests/scripts/docs_generic_deck.sh
    -
    -
    -
    -
    -
    -

    Rotation, translation, and zoom

    -

    This example relies on the simulation results in opm-tests. If you -download the files in that folder, then by using the plopm tool:

    -
    plopm -i NORNE_ATW2013 -s ,,1
    -
    -
    -

    these are some of the generated figures:

    -_images/norne.png -

    In order to reduce the white space outside the active cells, as well as to rotate the grid and translate it, this can be ahieved by:

    -
    plopm -i NORNE_ATW2013 -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -fz 8
    -
    -
    -_images/norne_transformed.png -

    To show all faults in the model and to only show the ones connected all along the z direction, this can be achieved by:

    -
    plopm -i NORNE_ATW2013 -v faults -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1
    -plopm -i NORNE_ATW2013 -v faults -s ,,1:22 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -agg max
    -
    -
    -_images/norne_faults.png -

    To show all wells in the model and to only show the ones with at least one perforation on the top layer, this can be achieved by:

    -
    plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 -fn "norne_wells_global"
    -plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8  -fn "norne_wells"
    -
    -
    -_images/norne_wells.png -
    -

    Note

    -

    For plotting the faults and wells, they must be specified in the input deck (no via include files).

    -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_rotation_translation_zoom.sh):

    -
    . ./tests/scripts/docs_rotation_translation_zoom.sh
    -
    -
    -
    -
    -
    -

    Projections and subfigures

    -

    Here is an example of making a single figure plotting subfigures and using different approaches to project the quantities:

    -
    plopm -i NORNE_ATW2013 -v 'index_k,permx,poro' -s ',,1:22 ,,1:22 ,,1:22' -agg 'first,arithmetic,max' -sg 1,3 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 24,10 -c 'PuOr,vanimo,jet' -cbf '.0f,.0f,.2f' -cbn '2,4,8' -st 0 -t "Top k values using first  Averaged permx using arithmetic  Values of porosity using max" -fz 18
    -
    -
    -_images/norne_atw2013_poro_i%2Cj%2C1%3A22_t64.png -
    -

    Tip

    -

    All previous commands can be executed as (docs_projections_subfigures.sh):

    -
    . ./tests/scripts/docs_projections_subfigures.sh
    -
    -
    -
    -
    -
    -

    Histograms

    -

    Here is an example of two subfigures showing the histogram of the porosity and permeability in norne using 20 bins and norm and lognorm distributions -respectively, showing also the mean and std which can be used for sampling (see the test for additional examples):

    -
    plopm -i NORNE_ATW2013 -v poro,permx -hist '20,norm 20,lognorm' -ag 0 -sg 1,2 -fs 15,5 -ll 'upper center' -y '[0,10000] [0,23000]' -c '#7274b3,#cddb6e'
    -
    -
    -_images/norne_atw2013_permx.png -
    -

    Tip

    -

    All previous commands can be executed as (docs_histograms.sh):

    -
    . ./tests/scripts/docs_histograms.sh
    -
    -
    -
    -
    -
    -

    Caprock integrity

    -

    Since there is an increase of interest in regional models, then we add three new variables -v related to the caprock integrity, -i.e., the most top active cells in the given range -s:

    -
      -
    1. limipres = stress*z-p0, where stress can be set via the flag -sc (0.134 by default, a common value in literature).

    2. -
    3. overpres = p-stress*z, i.e., a negative value means the limit pressure has not been reached.

    4. -
    5. objepres is the ratio of overpres to limipres, i.e., the value is of order of one and this can be used in optimization routines.

    6. -
    -

    Motivated for objepres, then now we add an option for mode to write a csv with the non nan values, i.e., -m csv. -For example, if we would like to estimate these values for norne for future CCS:

    -
    plopm -i 'NORNE_ATW2013' -s ',,1:22 ,,1:22' -v limipres,overpres -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 15,10 -c Spectral,spring -sg 1,2 -rdl 1
    -plopm -i 'NORNE_ATW2013' -m csv -v objepres -s ',,1:22'
    -
    -
    -_images/norne_atw2013_overpres_i%2Cj%2C1%3A22_t64.png -
    -

    Tip

    -

    All previous commands can be executed as (docs_caprock_integrity.sh):

    -
    . ./tests/scripts/docs_caprock_integrity.sh
    -
    -
    -
    -
    -
    -

    Reading from csv files

    -

    Using the flag -cc allows to read values from csv files, allowing also to combine values from OPM Flow output files. To ilustrate this, -let us consider the pyopmspe11 tool.

    -
    -

    Tip

    -

    You can install pyopmspe11 tool by executing in the terminal: pip install git+https://github.com/OPM/pyopmspe11.git. -Read the documentation in there to get familiar with the benchmark and the format of the csv files.

    -
    -

    Then, let us consider the configuration file r1_Cart_10m.toml from the benchmark folder. In line 2 of -that file set the number of cpus for the run (in the original file is 32; if you do not have mpi support, simply remove mpi, i.e., mpirun -np 32). To lower the simulation time, -in line 10 set x_n to 420 and line 12 set z_n to 60. In addition, in line 51 remove the 1000 years of initialization, i.e., the injection should be:

    -
    inj = [[  25, 5, 1, 0.035, 10, 1,     0, 10],
    -       [  25, 5, 1, 0.035, 10, 1, 0.035, 10],
    -       [ 950, 5, 1,     0, 10, 1,     0, 10]]
    -
    -
    -

    Once you have installed pyopmspe11, then run the configuration file:

    -
    pyopmspe11 -i r1_Cart_10m.toml -o r1_Cart_10m -m deck_flow_data -g all -t 5 -r 70,1,30 -w 0.1 -fz 0
    -
    -
    -

    This generates the output folder r1_Cart_10m, where the OPM Flow output files and the csvs are generated. To compare the spatial maps of the CO2 mass -fraction from the simulation grid to the reporting grid (70 by 30), this can be achieved by:

    -
    plopm -v xco2l -i "r1_Cart_10m/R1_CART_10M r1_Cart_10m/spe11b_spatial_map_500y" -cc ";1,2,5" -sg 2,1 -rdl 1 -r 100 -fs 10,3 -st 0 -t "Simulation grid  Reporting grid" -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f
    -
    -
    -

    where the flag -cc “;1,2,5” has two main entries (number of input files) separated by ;, and the first entry is defaulted since the input it is -an OPM Flow file, while the second entry has three values, where the first two sets the columns in the csv where the x and y coordinates are, and the last entry (5) -it is the column for the plotted variable. The previous command generates the following figure:

    -_images/spe11b_spatial_map_500y_xco2l_csv_t100.png -

    To compare two summary quantities, this can be achiaved by:

    -
    plopm -i "r1_Cart_10m/spe11b_time_series r1_Cart_10m/R1_CART_10M" -v ",BWPR:256,1,5" -cc "1,3;" -sf "1e-5,1" -ls "solid,dotted" -lw "4,4" -yl "Sensor pressure [bar]" -llb "From csv file  From OPM Flow output file" -c "r,k"
    -
    -
    -

    where for summary variables, the flag -v “,BWPR:256,1,5” needs to have empty entries for corresponding csv -i files, and the flag -sf “1e-5,1” allows to convert the values in Pascal to bar from the csv file, multiplying by 1e-5. The previous command generates the following figure:

    -_images/spe11b_time_series_BWPR-1944.png -

    If you download the benchmark data from this website, then you could use plopm to compare simulation results. -For example, by downloading the spe11_opm1.zip, spe11_opm2.zip, -spe11_opm3.zip, and spe11_opm4.zip, then you could compare -your simulations with those results by (to remove the legend, add the flag -ll empty):

    -
    plopm -i "opm1/spe11b_time_series opm2/spe11b_time_series opm3/spe11b_time_series opm4/spe11b_time_series r1_Cart_10m/spe11b_time_series" -cc "1,4;1,4;1,4;1,4;1,4" -tu y -x "[0,1000]" -yl "dissA [kiloton]" -yf .1f -sf 1e-6 -c "#a8d8e3,#a8d8e3,#a8d8e3,#a8d8e3,#fc035a" -lw 5,5,5,5,5 -ls solid
    -
    -
    -_images/spe11b_time_series_csv_ens.png -

    and for the spatial maps:

    -
    plopm -i "opm1/spe11b_spatial_map_250y opm2/spe11b_spatial_map_250y opm3/spe11b_spatial_map_250y opm4/spe11b_spatial_map_250y r1_Cart_10m/spe11b_spatial_map_250y"  -cc "1,2,5;1,2,5;1,2,5;1,2,5;1,2,5" -sg 3,2 -rdl 1 -st 0 -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f -fs 14,4 -t "opm1  opm2  opm3  opm4  my simulation" -cbl 'Time 250 years, CO$_2$ mass fraction (liquid phase) [-]' -c inferno
    -
    -
    -_images/spe11b_spatial_map_250y_csv_csv_t-1.png -

    To make a GIF from csvs, then write “PLOPM” in the csv file name (e.g., ‘-i opm1/spe11b_spatial_map_PLOPMy’) where to read the given times from -r (see these examples from pyopmspe11).

    -
    -

    Tip

    -

    In general, the ability of plotting from csv files using the flag -cc is a game changer, expanding the applicability of plopm beyond the format of OPM Flow output files.

    -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_reading_csvs.sh):

    -
    . ./tests/scripts/docs_reading_csvs.sh
    -
    -
    -
    -
    -
    -

    Convert to VTK

    -

    Inside the examples folder, then we can create VTKs from the -OPM Flow simulation results (i.e., .EGRID, .INIT, .UNRST). For example, to create VTKS for the temperature, fipnum, the co2 mass, and the co2 mass fraction in the liquid phase -from the restart files from the initial (0) to the number 5 restart, using a OPM Flow build from source in a given path, this can be achieved by:

    -
    plopm -i SPE11B -v temp,fipnum,co2m,xco2l -vf Float32,UInt16,Float64,Float16 -r 0,5 -m vtk
    -
    -
    -
    -_images/vtk_temp.png -
    -

    Visualization using paraview of the grid and temperature after 25 years of CO2 injection.

    -
    -

    Note

    -

    It is possible to write directly VTKs from OPM Flow simulations by adding the flag --enable-vtk-output=true. -However, there are quantities that are not written (e.g., fipnum, flores), in addition to quantities not supported -such as component mass (e.g., co2, h2o). This is when plopm can be helpful.

    +

    OPM Flow is required to reproduce the examples with the supplied shell +scripts. Install it before running them; see +OPM Flow.

    Tip

    -

    All previous commands can be executed as (docs_convert_to_vtk.sh):

    -
    . ./tests/scripts/docs_convert_to_vtk.sh
    -
    -
    -
    -
    -
    -

    Rel perms and capillary pressure

    -

    plopm supports the plotting of saturation functions using the ‘-v’ flag, namely ‘krw’, ‘krg’, ‘krow’, ‘krog’, ‘pcow’, ‘pcog’, and ‘pcwg’. -By default, the saturation function is plotted for SATNUM=1. For a different table, this can be achieved by adding the number at the end of the variable, e.g., ‘pcog5’. -In addition, if the model includes hysteresis, then to plot both drainage and imbibition curves this can be achieved by adding ‘h’ at the end of the variable, e.g., ‘krg3h’. -However, by plotting individually the drainage and imbibition tables one can set the labels, colors, and styles for each of them.

    -
    plopm -i 'H2HYSTERESIS' -v krgh,krwh -llb "Hydrogen  Brine" -c r,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl ' Liquid saturation, $s_w$ [-]'  -ls solid,solid -xnt 6  -ynt 6
    -plopm -i 'H2HYSTERESIS' -v krg1,krg2,krw1,krw2 -llb "Drainage hydrogen  Imbibition hydrogen  Drainage brine  Imbibition brine" -c r,r,#0314fc,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,dashed,solid,dashed  -xnt 6  -ynt 6
    -plopm -i 'H2HYSTERESIS' -v pcwg -c k -x '[0,1]' -lw 5 -ll empty -fz 18 -fs 8,6 -yl 'Capillary pressure, $p_c$ [bar]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,dashed,solid,dashed  -xnt 6  -ylog 1
    -
    -
    -_images/saturation_functions.png -
    -

    Tip

    -

    These figures can be generated by (docs_rel_perms_and_capillary_pressure.sh):

    -
    . ./tests/scripts/docs_rel_perms_and_capillary_pressure.sh
    -
    -
    -
    -
    -
    -

    Different input files and ensembles

    -

    Let us assume we have two different runs in different folders for the spe11b case, where the firsts results are save -in a folder called spe11b, and simulation results where the injection rate has been increased are saved in a folder -called spe11b_larger_inj. Then, to plot the summary vector for both runs we can execute:

    -
    plopm -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B' -v 'fgmip,fgmip / 1E6,RGMDS:5' -yl '[kg]  [Kt]  [kg]' -tu w -fs 10,5 -c r,b -ls 'solid,dashed' -t 'Field gas mass in place  Converted to kilotonns   Dissolved CO$_2$ in facie 5' -fz 14 -sg 2,2 -rdl 1 -ll empty,empty,empty,center -fn comparison
    -
    -
    -_images/comparison.png - -

    Here, using subplots, we plot the gas in place in kilograms, we convert this to kilotonnes, the dissolve CO2 mass in facie 5, and the time is shown in weeks.

    -
    -

    Tip

    -

    For any summary variable, one can give the path to more than two different simulation cases, just by separating the folder paths by spaces in the -i.

    -
    -

    To look at the difference between these two simulations for the dynamic variable sgas at the restar step 3, this can be achieved by executing:

    -
    plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1
    -
    -
    -_images/sgas_diff.png -

    To changue the colormap and setting the colorbar limits manually, this can be achieved by:

    -
    plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 -c tab20c_r -cl '[0,0.8]' -cbn 9 -cbf 0.1 -fn formated
    -
    -
    -_images/sgas_diff_edit.png -

    The ensemble folder provides a Python file to generate two different -ensembles using pyopmnearwell, where the residual gas saturation is randomly generated.

    -
    -

    Tip

    -

    You can install pyopmnearwell by executing in the terminal: pip install git+https://github.com/cssr-tools/pyopmnearwell.git.

    -
    -

    Below are two of the generated figures after executing the script (additional figures are generated to show the functionality of the -ens flag):

    -
    -_images/ensemble.png -
    -

    Example of visualizing ensembles using plopm (example0.png and example3_formated.png respectively).

    -
    -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_different_files_and_ensembles.sh):

    -
    . ./tests/scripts/docs_different_files_and_ensembles.sh
    -
    -
    -
    -
    -
    -

    Filters

    -

    Using the flag -flt allows to remove cells given conditions separated by ‘&’, and it is also possible to set different filters in subfigures. For example:

    -
    plopm -i 'SPE11B SPE11B SPE11B' -flt ',fipnum >= 2 & fipnum != 4,satnum == 5' -v fipnum -sg 3,1 -rdl 1 -cbf .0f -fs 7,4 -u resdata -cbp 0.15,0.97,0.7,0.02 -t "No filter  fipnum >= 2 and fipnum != 4  satnum == 5" -st 0
    -
    -
    -_images/filter_opm.png -
    -

    Note

    -

    It is possible to set dynamic variables to filter as well such as sgas and pressure. However, this requires to output the dynamic pore volume, i.e., RPORV. -This can be achieved by adding to the deck RPORV to the RPTRST in the SOLUTION and SCHEDULE section (and running the simulations).

    -
    -
    -

    Tip

    -

    All previous commands can be executed as (docs_filters.sh):

    -
    . ./tests/scripts/docs_filters.sh
    -
    -
    -
    -
    -
    -

    GIF and mask

    -

    To create a GIF and mask the results using the satnum numbers (any variable should be supported) for the different rock properties, this can be achieved by (here we have add -terminal commands to generate the data to generate figures by installing pyopmspe11, downloading the corresponding configuration files, creating one with higher injection -rate, and after using plopm):

    -
    pip install git+https://github.com/cssr-tools/pyopmspe11.git
    -curl -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml
    -cp spe11b.toml spe11b_larger_inj.toml
    -sed -i.bak 's/0.035/0.07/g' spe11b_larger_inj.toml && rm -fz spe11b_larger_inj.toml.bak
    -pyopmspe11 -i spe11b.toml -o spe11b -fz 0
    -pyopmspe11 -i spe11b_larger_inj.toml -o spe11b_larger_inj -fz 0
    -plopm -v xco2l -sg 1,2 -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B_LARGER_INJ' -fs 16,2.5 -mv satnum -r 0,1,2,3,4,5 -m gif -dpi 1000 -t "spe11b  spe11b larger injection" -fz 16 -gi 1000 -gl 1 -cbf .2f -cbp 0.30,0.01,0.4,0.02
    -
    -
    -_images/xco2l.gif -

    If -r is not provided, then by default the GIF uses all restart steps. For selected restart steps, these can be given separated by commas, e.g., -r 1,4,5.

    -

    To generate a single GIF of the gas saturation without masking and showing the grid:

    -
    plopm -i 'spe11b/SPE11B' -v sgas -tu y -c cet_cwr  -ge 'black,5e-3' -fs 16,5 -m gif -dpi 1000 -fz 20 -gi 1000 -gl 1 -cbf .2f -asp 0 -xu km -yu km -xf .1f -yf .1f -cbn 5 -cbl 'Gas saturation [-]'
    -
    -
    -_images/spe11b_sgas.gif -

    Here we have changed the units for time from days to years using the -tu flag. To remove the dynamic times in the GIF, set -tu empty.

    -
    -

    Tip

    -

    All previous commands can be executed as (docs_gif_mask.sh):

    -
    . ./tests/scripts/docs_gif_mask.sh
    -
    -
    -
    -
    -
    -

    Graphical abstract

    -

    Here we describe how to generate the ilustrations in the graphical abstract. -The first ilustration is generated from the SPE11B model using pyopmspe11:

    -
    pip install git+https://github.com/OPM/pyopmspe11.git
    -curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml
    -curl -L https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11b.toml -o spe11b_higher_rate.toml
    -ex -s +'51c|inj = [[25, 5, 1, 0.07, 10, 1, 0.07, 10]]' -c x spe11b_higher_rate.toml
    -sed -i.bak 's/0.035/0.07/g' spe11b_higher_rate.toml
    -pyopmspe11 -i spe11b.toml -o spe11b -fz 0
    -pyopmspe11 -i spe11b_higher_rate.toml -o spe11b_higher_rate -fz 0
    -plopm -i 'spe11b/SPE11B spe11b_higher_rate/SPE11B_HIGHER_RATE' -v 'fgmip * 1e-6' -c 'r,b' -tu y -xf .0f -lw 2 -label 'Base case  Higher injection rate' -xnt 6 -yl 'Total CO$_2$ mass [Kt]' -fz 18 -t 'Comparing two runs of the SPE11B model'
    -
    -
    -

    The ilustration in the middle is generated from the NORNE_ATW2013.DATA model:

    -
    git clone https://github.com/OPM/opm-data.git
    -flow opm-data//norne/NORNE_ATW2013.DATA --enable-dry-run=1
    -plopm -i opm-data//norne/NORNE_ATW2013 -v permx -clog 1 -rot 65 -s ,,1 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -t "Top view of NORNE" -xu km -yu km -fz 16 -ge 'black,1e-2' -xf .1f -yf .1f -fs 8,8
    -
    -
    -

    The ilustration in the right is generated from the SPE11C model using pyopmspe11, specially the corner-point case with -more than a 100 million cells (r4_cp_8m-8mish-8mish.toml). Since that -case requires a big computer (run with 1024 CPUs), then the steps below are applied to a version of the SPE11C model with fewer cells that can be run locally:

    -
    pip install git+https://github.com/OPM/pyopmspe11.git
    -curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11c.toml
    -pyopmspe11 -i spe11c.toml -o spe11c -fz 0
    -plopm -i spe11c/SPE11C -v satnum,xco2l -vf UInt16,Float16 -r 0,5 -m vtk
    -
    -
    -

    The above commands will generate the SPE11C.pvd, SPE11C-000.vtu, and SPE11C_0005.vtu files, which then can be open using paraview, -and using the interactive GUI one can then obtain the most-rigthed figure in the abstract (e.g., using the facie numbers stored as satnum to add the background).

    -
    -

    Tip

    -

    All previous commands can be executed as (docs_graphical_abstract.sh):

    -
    . ./tests/scripts/docs_graphical_abstract.sh
    -
    -
    +

    Generate all documented figures from the repository root:

    +
    . tests/scripts/docs_all.sh
    +
    +
    +
    + +
    +
    +
    -
    -
    -
    + + + + +
+ +
+ + + + + +
+ +
+ + + - + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/examples/animations.html b/docs/examples/animations.html new file mode 100644 index 0000000..c9f8994 --- /dev/null +++ b/docs/examples/animations.html @@ -0,0 +1,650 @@ + + + + + + + + + + + GIFs and masks — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

GIFs and masks#

+

Animate results and apply masks.

+

Create a masked GIF comparing two cases.

+
plopm -v xco2l -sg 1,2 -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B_LARGER_INJ' -fs 16,2.5 -mv satnum -r 0,1,2,3,4,5 -m gif -dpi 1000 -t 'spe11b  spe11b larger injection' -fz 16 -gi 1000 -gl 1 -cbf .2f -cbp 0.30,0.01,0.4,0.02
+
+
+
+../_images/xco2l.gif + +
+

Create an unmasked gas-saturation GIF with grid edges.

+
plopm -i spe11b/SPE11B -v sgas -tu y -c cet_cwr -ge 'black,5e-3' -fs 16,5 -m gif -dpi 1000 -fz 20 -gi 1000 -gl 1 -cbf .2f -asp 0 -xu km -yu km -xf .1f -yf .1f -cbn 5 -cbl 'Gas saturation [-]'
+
+
+
+../_images/spe11b_sgas.gif + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_gif_mask.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/caprock.html b/docs/examples/caprock.html new file mode 100644 index 0000000..8240977 --- /dev/null +++ b/docs/examples/caprock.html @@ -0,0 +1,643 @@ + + + + + + + + + + + Caprock integrity — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Caprock integrity#

+

Evaluate pressure limits.

+

limipres, overpres, and objepres support caprock-integrity analysis.

+
plopm -i NORNE_ATW2013 -s ',,1:22 ,,1:22' -v limipres,overpres -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 15,10 -c Spectral,spring -sg 1,2 -rdl 1
+plopm -i NORNE_ATW2013 -m csv -v objepres -s ',,1:22'
+
+
+
+../_images/norne_atw2013_overpres_i%2Cj%2C1%3A22_t64.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_caprock_integrity.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/colormaps.html b/docs/examples/colormaps.html new file mode 100644 index 0000000..8092a52 --- /dev/null +++ b/docs/examples/colormaps.html @@ -0,0 +1,642 @@ + + + + + + + + + + + Colormaps — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Colormaps#

+

Use named, RGB, and HEX colormaps.

+

Use plopm -c with Matplotlib or Colorcet names, RGB values, or HEX colors.

+
plopm -i SPE11B -v satnum,fipnum,disperc -c '193;147;56 127;148;191 193;127;97 181;73;57 81;124;66 101;64;147 134;133;130',cet_glasbey_bw,'#b6c406 #fffa86' -sg 3,1 -rdl 1 -cbn 3,6,2 -cbf .0f,.0f,.1f -fs 7,4
+
+
+
+../_images/spe11b_disperc_i%2C1%2Ck_t5.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_colormaps.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/csv.html b/docs/examples/csv.html new file mode 100644 index 0000000..b0df9c1 --- /dev/null +++ b/docs/examples/csv.html @@ -0,0 +1,660 @@ + + + + + + + + + + + Reading CSV files — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Reading CSV files#

+

Combine CSV and OPM Flow data.

+

Use plopm -cc to combine CSV and OPM Flow data.

+
plopm -v xco2l -i 'r1_Cart_10m/R1_CART_10M r1_Cart_10m/spe11b_spatial_map_500y' -cc ';1,2,5' -sg 2,1 -rdl 1 -r 100 -fs 10,3 -st 0 -t 'Simulation grid  Reporting grid' -cbp 0.35,0.97,0.3,0.02 -yu km -xu km -yf .1f -xf .1f -cbn 5 -xnt 8 -cbf .2f
+
+
+
+../_images/spe11b_spatial_map_500y_xco2l_csv_t100.png + +
+

Compare a CSV series with an OPM summary vector.

+
plopm -i 'r1_Cart_10m/spe11b_time_series r1_Cart_10m/R1_CART_10M' -v ',BWPR:256,1,5' -cc '1,3;' -sf '1e-5,1' -ls 'solid,dotted' -lw '4,4' -yl 'Sensor pressure [bar]' -llb 'From CSV file  From OPM Flow output file' -c 'r,k'
+
+
+
+../_images/spe11b_time_series_BWPR-1944.png + +
+

Compare several benchmark series.

+
+../_images/spe11b_time_series_csv_ens.png + +
+

Compare several benchmark spatial maps.

+
+../_images/spe11b_spatial_map_250y_csv_csv_t-1.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_reading_csvs.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/ensembles.html b/docs/examples/ensembles.html new file mode 100644 index 0000000..a72e7b6 --- /dev/null +++ b/docs/examples/ensembles.html @@ -0,0 +1,663 @@ + + + + + + + + + + + Different inputs and ensembles — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Different inputs and ensembles#

+

Compare cases and ensembles.

+

Compare summary quantities from two simulations.

+
plopm -i 'spe11b/SPE11B spe11b_larger_inj/SPE11B' -v 'fgmip,fgmip / 1E6,RGMDS:5' -yl '[kg]  [Kt]  [kg]' -tu w -fs 10,5 -c r,b -ls 'solid,dashed' -t 'Field gas mass in place  Converted to kilotonnes  Dissolved CO$_2$ in facies 5' -fz 14 -sg 2,2 -rdl 1 -ll empty,empty,empty,center -fn comparison
+
+
+
+../_images/comparison.png + +
+

Subtract one case from another.

+
plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1
+
+
+
+../_images/sgas_diff.png + +
+

Format the difference map.

+
plopm -i spe11b_larger_inj/SPE11B -v sgas -r 3 -di spe11b/SPE11B -hide 0,0,0,1 -c tab20c_r -cl '[0,0.8]' -cbn 9 -cbf 0.1 -fn formated
+
+
+
+../_images/sgas_diff_edit.png + +
+

Use plopm -ens for ensemble statistics.

+
+../_images/ensemble.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_different_files_and_ensembles.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/filters.html b/docs/examples/filters.html new file mode 100644 index 0000000..0e100af --- /dev/null +++ b/docs/examples/filters.html @@ -0,0 +1,643 @@ + + + + + + + + + + + Filters — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Filters#

+

Select cells with conditions.

+

Join conditions for one input with & and separate input filters with commas.

+
plopm -i 'SPE11B SPE11B SPE11B' -flt ',fipnum >= 2 & fipnum != 4,satnum == 5' -v fipnum -sg 3,1 -rdl 1 -cbf .0f -fs 7,4 -cbp 0.15,0.97,0.7,0.02 -t 'No filter  fipnum >= 2 and fipnum != 4  satnum == 5' -st 0
+
+
+
+../_images/filter_opm.png + +
+

Dynamic filters require RPORV in RPTRST.

+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_filters.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/generic-deck.html b/docs/examples/generic-deck.html new file mode 100644 index 0000000..48be447 --- /dev/null +++ b/docs/examples/generic-deck.html @@ -0,0 +1,651 @@ + + + + + + + + + + + Generic deck — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Generic deck#

+

Plot a generic OPM Flow model.

+

Plot vertical permeability from SPE10 MODEL 2.

+
plopm -i SPE10_MODEL2 -v permz -s ,4, -clog 1 -xu km -yu km -xnt 6 -yf .2f -t 'K$_z$ at the fourth slice in the xz plane' -cl '[1e-7,1e3]'
+
+
+
+../_images/spe10_model2_permz_%2A%2C4%2C%2A_t0.png + +
+

Plot the grid and wells from above.

+
plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v grid -hide 0,0,1,0
+plopm -i SPE10_MODEL2 -s ,,1 -fs 3,4 -fz 8 -v wells -hide 0,0,0,1
+
+
+
+../_images/wells.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_generic_deck.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/graphical-abstract.html b/docs/examples/graphical-abstract.html new file mode 100644 index 0000000..73e28ed --- /dev/null +++ b/docs/examples/graphical-abstract.html @@ -0,0 +1,659 @@ + + + + + + + + + + + Graphical abstract — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Graphical abstract#

+

Reproduce the graphical abstract.

+

The graphical abstract combines an SPE11B summary comparison, a Norne map, and an SPE11C VTK visualization.

+
+../_images/plopm.png + +
+

The plopm graphical abstract.#

+
+
+

Generate the SPE11B comparison.

+
plopm -i 'spe11b/SPE11B spe11b_higher_rate/SPE11B_HIGHER_RATE' -v 'fgmip * 1e-6' -c 'r,b' -tu y -xf .0f -lw 2 -llb 'Base case  Higher injection rate' -xnt 6 -yl 'Total CO$_2$ mass [Kt]' -fz 18 -t 'Comparing two runs of the SPE11B model'
+
+
+

Generate the Norne map.

+
git clone https://github.com/OPM/opm-data.git
+flow opm-data/norne/NORNE_ATW2013.DATA --enable-dry-run=1
+plopm -i opm-data/norne/NORNE_ATW2013 -v permx -clog 1 -rot 65 -s ,,1 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -t 'Top view of NORNE' -xu km -yu km -fz 16 -ge 'black,1e-2' -xf .1f -yf .1f -fs 8,8
+
+
+

Generate SPE11C VTK files.

+
pip install git+https://github.com/OPM/pyopmspe11.git
+curl -L -O https://raw.githubusercontent.com/OPM/pyopmspe11/refs/heads/main/examples/spe11c.toml
+pyopmspe11 -i spe11c.toml -o spe11c -fz 0
+plopm -i spe11c/SPE11C -v satnum,xco2l -vf UInt16,Float16 -r 0,5 -m vtk
+
+
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_graphical_abstract.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/hello-world.html b/docs/examples/hello-world.html new file mode 100644 index 0000000..d7b6fb2 --- /dev/null +++ b/docs/examples/hello-world.html @@ -0,0 +1,666 @@ + + + + + + + + + + + Hello world — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Hello world#

+

Create maps, summary plots, and cell time series.

+

Run the default command from the examples directory.

+
plopm -i SPE11B
+
+
+
+../_images/spe11b_satnum_%2A%2C1%2C%2A_t5.png + +
+

Plot gas saturation at restart step 4.

+
plopm -i SPE11B -v sgas -r 4 -cbn 3 -c cubehelix -cbt '[0, middle, 0.9]'
+
+
+
+../_images/spe11b_sgas_i%2C1%2Ck_t4.png + +
+

Plot field gas in place.

+
plopm -i SPE11B -v fgip -c b -ls dotted -fz 12 -fs 5,5 -lw 4 -tu dates
+
+
+
+../_images/fgip.png + +
+

Plot pressure increase at three cells.

+
plopm -i 'SPE11B SPE11B SPE11B' -v 'pressure - 0pressure' -s '1,1,1 41,1,29 83,1,58' -llb 'Top left corner  Middle  Right lower corner' -yl 'Pressure increase at the sensor locations [bar]' -yf .0f -xnt 11 -tu dates
+
+
+
+../_images/spe11b_pressure-0pressure.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_hello_world.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/histograms.html b/docs/examples/histograms.html new file mode 100644 index 0000000..edb277e --- /dev/null +++ b/docs/examples/histograms.html @@ -0,0 +1,642 @@ + + + + + + + + + + + Histograms — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Histograms#

+

Plot property distributions.

+

Plot porosity and permeability histograms with fitted distributions.

+
plopm -i NORNE_ATW2013 -v poro,permx -hist '20,norm 20,lognorm' -ag 0 -sg 1,2 -fs 15,5 -ll 'upper center' -y '[0,10000] [0,23000]' -c '#7274b3,#cddb6e'
+
+
+
+../_images/norne_atw2013_permx.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_histograms.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/projections.html b/docs/examples/projections.html new file mode 100644 index 0000000..3d0c8ef --- /dev/null +++ b/docs/examples/projections.html @@ -0,0 +1,642 @@ + + + + + + + + + + + Projections and subfigures — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Projections and subfigures#

+

Combine projection methods in one figure.

+

Apply a different aggregation to each projected quantity.

+
plopm -i NORNE_ATW2013 -v 'index_k,permx,poro' -s ',,1:22 ,,1:22 ,,1:22' -agg 'first,arithmetic,max' -sg 1,3 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fs 24,10 -c 'PuOr,vanimo,jet' -cbf '.0f,.0f,.2f' -cbn '2,4,8' -st 0 -t 'Top k values using first  Averaged permx using arithmetic  Values of porosity using max' -fz 18
+
+
+
+../_images/norne_atw2013_poro_i%2Cj%2C1%3A22_t64.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_projections_subfigures.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/relative-permeability.html b/docs/examples/relative-permeability.html new file mode 100644 index 0000000..9582bef --- /dev/null +++ b/docs/examples/relative-permeability.html @@ -0,0 +1,643 @@ + + + + + + + + + + + Relative permeability and capillary pressure — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Relative permeability and capillary pressure#

+

Plot saturation functions.

+

Append a SATNUM table number or h for hysteresis curves.

+
plopm -i H2HYSTERESIS -v krgh,krwh -llb 'Hydrogen  Brine' -c r,#0314fc -x '[0,1]' -lw 5 -fz 18 -fs 8,6 -yl 'Relative permeability, $k_r$ [-]' -xl 'Liquid saturation, $s_w$ [-]' -ls solid,solid -xnt 6 -ynt 6
+plopm -i H2HYSTERESIS -v pcwg -c k -x '[0,1]' -lw 5 -ll empty -fz 18 -fs 8,6 -yl 'Capillary pressure, $p_c$ [bar]' -xl 'Liquid saturation, $s_w$ [-]' -xnt 6 -ylog 1
+
+
+
+../_images/saturation_functions.png + +
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_rel_perms_and_capillary_pressure.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/transformations.html b/docs/examples/transformations.html new file mode 100644 index 0000000..8d00a75 --- /dev/null +++ b/docs/examples/transformations.html @@ -0,0 +1,672 @@ + + + + + + + + + + + Rotation, translation, and zoom — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Rotation, translation, and zoom#

+

Transform, crop, and inspect Norne.

+

Start with the Norne top view.

+
plopm -i NORNE_ATW2013 -s ,,1
+
+
+
+../_images/norne.png + +
+

Rotate, translate, and crop the grid.

+
plopm -i NORNE_ATW2013 -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,7600]' -fz 8
+
+
+
+../_images/norne_transformed.png + +
+

Apply the same transformation to faults.

+
plopm -i NORNE_ATW2013 -v faults -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1
+plopm -i NORNE_ATW2013 -v faults -s ,,1:22 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -agg max
+
+
+
+../_images/norne_faults.png + +
+

Plot all wells and wells on the selected layer.

+
plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -gr 1 -fn norne_wells_global
+plopm -i NORNE_ATW2013 -v wells -s ,,1 -rot 65 -tr '[6456335.5,-3476500]' -x '[0,5600]' -y '[0,8800]' -fz 8 -fn norne_wells
+
+
+
+../_images/norne_wells.png + +
+
+

Note

+

Faults and wells must be declared directly in the input deck.

+
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_rotation_translation_zoom.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/examples/vtk.html b/docs/examples/vtk.html new file mode 100644 index 0000000..55669d1 --- /dev/null +++ b/docs/examples/vtk.html @@ -0,0 +1,645 @@ + + + + + + + + + + + Convert to VTK — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Convert to VTK#

+

Export data for ParaView.

+

Export selected variables for restart steps 0 and 5.

+
plopm -i SPE11B -v temp,fipnum,co2m,xco2l -vf Float32,UInt16,Float64,Float16 -r 0,5 -m vtk
+
+
+
+../_images/vtk_temp.png + +
+

Grid and temperature after 25 years of CO2 injection, viewed in ParaView.#

+
+
+
+

Reproduce this example#

+

Run the complete workflow from the repository root:

+
. ./tests/scripts/docs_convert_to_vtk.sh
+
+
+
+ +
+

Back to the examples gallery

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/genindex.html b/docs/genindex.html index 62d384b..98bdc97 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -1,84 +1,444 @@ - - - - - - Index — plopm documentation - - - - - - - - - - - + + + + + + + + Index — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + -
- -
- + +
+ + + + + + + + - + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 55cd6fb..d6ce142 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,208 +1,661 @@ - - - - - - - Welcome to plopm’s documentation! — plopm documentation - - - - - - - - - - - + + + + + + + + + plopm — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + - -
- - -
- -
-
-
-
+ +
+ + + + + + + +
-
-
- -
-

Welcome to plopm’s documentation!

- + + +
+ + + + + +
+ + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ +
+

plopm#

+

A lightweight and flexible tool for visualization and postprocessing of +OPM Flow geological models.

+

plopm generates publication-ready PNG figures, GIF animations, CSV data, +and VTK files from OPM Flow simulation output.

+
+
+
+
+
+
+ Get started
+

Learn what plopm does and where to begin.

+
+Introduction
+
+
+
+
+
+ Install plopm
+

Install plopm and the optional OPM Flow and LaTeX dependencies.

+
+Installation
+
+
+
+
+
+ Follow the tutorial
+

Progress from a first PNG to projections, comparisons, and data export.

+
+Tutorial
+
+
+
+
+
+ Explore examples
+

Browse task-oriented examples with figures and reproducible scripts.

+
+Examples
+
+
+
+
+

Quick installation#

+

Install the current development version from GitHub:

+
pip install git+https://github.com/cssr-tools/plopm.git
+
+
+

See Installation for virtual environments, source installation, OPM +Flow, and optional LaTeX support.

+
+
+

Quick start#

+

Plot pressure on the plane at j=1:

+
plopm -i SPE11B -v pressure -s ,1,
+
+
+

Display the built-in help or list the variables available for an input case:

+
plopm --help
+plopm -i SPE11B -lv 1
+
+
+

See the Tutorial for a guided workflow and the Command-line reference for +exact syntax and option descriptions.

+
+
+

What can plopm do?#

+
+
+
+
+
+
+Plot reservoir properties
+

Visualize static and dynamic quantities on model slices and projections.

+
+
+
+
+
+
+
+Compare simulations
+

Plot multiple cases, differences, summary vectors, and ensembles.

+
+
+
+
+
+
+
+Create reusable outputs
+

Export PNG figures, GIF animations, CSV data, and VTK datasets.

+
+
+
+
+
+
+
+Support reproducible workflows
+

Reproduce visualization and postprocessing tasks from shell scripts.

+
+
+
+
+
+
-
-

Indices and tables

-
-
-
- - - - + - + + + + + + +
+ +
+ +
+ + + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/installation.html b/docs/installation.html index b778d49..e9135ea 100644 --- a/docs/installation.html +++ b/docs/installation.html @@ -1,231 +1,751 @@ - - - - - - - Installation — plopm documentation - - - - - - - - - - - + + + + + + + + + Installation — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + - - -
- -
-
-
-
+ + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ +
-
-
- +
+ + + + + +
+
-

Installation

-

The following steps work installing the dependencies in Linux via apt-get or in macOS using brew or macports. -While using packages managers such as Anaconda, Miniforge, or Mamba might work, these are not tested. -The supported Python versions are 3.12 to 3.14.

+

Installation#

+

The following instructions cover dependency installation on Linux with +apt-get and on macOS with Homebrew or MacPorts. Package managers such as +Anaconda, Miniforge, and Mamba might work, but they are not tested.

+

plopm supports Python 3.12 to 3.14.

-

Python package

-

To install the plopm executable from the development version in an existing Python environment:

-
pip install git+https://github.com/cssr-tools/plopm.git
+

Python package#

+

Install the development version of plopm in an existing Python +environment:

+
pip install git+https://github.com/cssr-tools/plopm.git
 
-

If you are interested in a specific version (e.g., v2026.04) or in modifying the source code, then you can clone the repository and -install the Python requirements in a virtual environment with the following commands:

-
# Clone the repo
+

To install a specific version, modify the source code, or contribute to the +project, clone the repository and create a virtual environment:

+
# Clone the repository
 git clone https://github.com/cssr-tools/plopm.git
-# Get inside the folder
+
+# Enter the repository
 cd plopm
-# For a specific version (e.g., v2026.04), or skip this step (i.e., edge version)
+
+# Optional: select a release, or skip this step to use the development version
 git checkout v2026.04
-# Create virtual environment
+
+# Create a virtual environment
 python3 -m venv vplopm
-# Activate virtual environment
+
+# Activate the virtual environment
 source vplopm/bin/activate
-# Upgrade pip, setuptools, and wheel
+
+# Upgrade the packaging tools
 pip install --upgrade pip setuptools wheel
-# Install the plopm package
+
+# Install plopm in editable mode
 pip install -e .
-# For contributions/testing/linting, install the dev-requirements
+
+# Optional: install requirements for contributions, testing, and linting
 pip install -r dev-requirements.txt
 

Tip

-

Typing git tag -l writes all available specific versions.

+

Run git tag -l to list the available releases.

-
-

Note

-

For not macOS users, to install the (optional but recommended) dependencies used for the figure’s LaTeX formatting, execute

-

sudo apt-get install texlive-fonts-recommended texlive-fonts-extra dvipng cm-super

-

For macOS users, the LaTeX dependency can be installed from https://www.tug.org/mactex/.

+
+
+

Optional LaTeX formatting#

+

LaTeX support is optional but recommended for figure formatting.

+

On Linux distributions using apt-get, install:

+
sudo apt-get install texlive-fonts-recommended texlive-fonts-extra dvipng cm-super
+
+

On macOS, install MacTeX.

-

OPM Flow

-

To use the convertion from OPM Flow output files (i.e., .EGRID, .INIT, .UNRST) to vtk, you also need to install:

- +

OPM Flow#

+

OPM Flow is required to convert OPM Flow output files such as .EGRID, +.INIT, and .UNRST to VTK. Use OPM Flow Release 2026.04 or the current +master branches.

+

See the OPM project website for general +information.

-

Binary packages

-

See the downloading and installing OPM Flow online documentation for -instructions to install the binary packages in Ubuntu and Red Hat Enterprise Linux, and for other platforms which are -supported either via source builds or through running a virtual machine.

+

Binary packages#

+

See the OPM Flow download and installation instructions for binary packages on Ubuntu and Red +Hat Enterprise Linux. The same page describes other supported platforms, +including source builds and virtual-machine-based installations.

Tip

-

See the CI.yml script -for installation of OPM Flow (binary packages), LaTeX (optional) libraries, and the plopm package in Ubuntu 26.04 and Python 3.14.

+

The plopm CI workflow +shows the installation of OPM Flow binary packages, optional LaTeX +libraries, and plopm on Ubuntu 26.04 with Python 3.14.

-
-

Source build in Linux/Windows

-

If you are a Linux user (including the Windows subsystem for Linux), then you could try to build Flow (after installing the prerequisites) from the master branches with mpi support by running -in the terminal the following lines (which in turn should build flow in the folder ./build/opm-simulators/bin/flow):

-
CURRENT_DIRECTORY="$PWD"
-
-mkdir build
-
-for repo in common grid simulators
-do  git clone https://github.com/OPM/opm-$repo.git
-    mkdir build/opm-$repo
-    cd build/opm-$repo
-    cmake -DUSE_MPI=1 -DWITH_NDEBUG=1 -DCMAKE_BUILD_TYPE=Release $CURRENT_DIRECTORY/opm-$repo
-    if [[ $repo == simulators ]]; then
-        make -j5 flow
-    else
-        make -j5 opm$repo
-    fi
-    cd ../..
-done
+
+

Source build on Linux#

+

After installing the OPM prerequisites, build Flow from the current master +branches with MPI support. The following commands create the executable at +./build/opm-simulators/bin/flow:

+
CURRENT_DIRECTORY="$PWD"
+
+mkdir build
+
+for repo in common grid simulators
+do
+    git clone https://github.com/OPM/opm-$repo.git
+    mkdir build/opm-$repo
+    cd build/opm-$repo
+    cmake -DUSE_MPI=1 -DWITH_NDEBUG=1 -DCMAKE_BUILD_TYPE=Release $CURRENT_DIRECTORY/opm-$repo
+    if [[ $repo == simulators ]]; then
+        make -j5 flow
+    else
+        make -j5 opm$repo
+    fi
+    cd ../..
+done
 

Tip

-

You can create a .sh file (e.g., build_opm_mpi.sh), copy the previous lines, and run in the terminal . ./build_opm_mpi.sh

+

Save the commands in a shell script, for example +build_opm_mpi.sh, and run it with:

+
. ./build_opm_mpi.sh
+
+
+
+

The resulting Flow executable can be selected explicitly when generating VTK +files:

+
plopm -i SPE11C -m vtk -fp ./build/opm-simulators/bin/flow
+
+

See plopm -fp and VTK output.

-
-

Brew formula for macOS

-

For macOS, there are no available binary packages, so OPM Flow needs to be built from source. Recently, a formula to build flow using brew has -been added in https://github.com/cssr-tools/homebrew-opm. -Then, you can try to install flow (v2026.07 interim release) by simply typing:

+
+

Homebrew formula for macOS#

+

Binary OPM Flow packages are not available for macOS, so Flow must be built +from source. The cssr-tools/homebrew-opm repository provides a Homebrew +formula for this purpose.

+

Install the OPM Flow v2026.07 interim release with:

brew tap cssr-tools/opm
 brew trust cssr-tools/opm
 brew install cssr-tools/opm/opm-simulators -y
 
-

You can check if the installation of OPM Flow succeded by typing in the terminal flow --help.

+

Verify the installation:

+
flow --help
+
+

Tip

-

See the actions in the cssr-tools/homebrew-opm repository.

+

See the homebrew-opm workflow results for tested builds.

-
-

Source build in macOS

-

See this repository dedicated to build OPM Flow from source in macOS 26 (GitHub actions), and tested with pycopm, another repository in cssr-tools.

+
+

Source build on macOS#

+

See the OPM-Flow_macOS repository for a source-build workflow for +OPM Flow on macOS 26. The workflow runs with GitHub Actions and is tested with +pycopm, another project in the cssr-tools organization.

+
+

Next steps#

+
    +
  • Follow the Tutorial to progress from a first PNG to SPE11C +projections and comparisons.

  • +
  • Browse the Examples for task-oriented workflows.

  • +
  • Use the Command-line reference for syntax and option descriptions.

  • +
+
-
-
-
+ + + + + + + +
+ + + + +
+ - +
+ +
+ + + +
+ +
+ + + + + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/introduction.html b/docs/introduction.html index 795eea5..dae1173 100644 --- a/docs/introduction.html +++ b/docs/introduction.html @@ -1,613 +1,641 @@ - - - - - - - Introduction — plopm documentation - - - - - - - - - - - + + + + + + + + + Introduction — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + - - -
- -
-
-
-
    -
  • - -
  • - View page source -
  • + + + + + +
    + + +
    +
    + +
    +
    + +
    + +
    + +
    -

    Options may be combined to configure the data selection, plot appearance, -and output. For example:

    -
    plopm -i SPE11B -v pressure -s ",,5" -c viridis -cl "[100,300]" -o results -fn pressure_k5
    -
    + +
    + +
    -
-
-

Argument syntax

-

Many plopm options accept multiple values or specifications. Commas normally -separate components within one specification, while spaces separate repeated -specifications for different inputs, variables, or plots. Enclose the complete -argument in quotes when it contains spaces.

-

For example:

-
plopm -v "pressure,sgas"
-plopm -s "1,1,1 41,1,29 83,1,58"
-plopm -y "[0,10000] [0,23000]"
-plopm -hist "50,norm 20,lognorm 100"
-plopm -clog "1,1,0"
-
-

The separators have the following general meanings:

+ + + + + +
+ + _images/plopm.png +
+

Introduction#

+

plopm is a lightweight command-line tool for visualization and +postprocessing of OPM Flow geological models.

+

It can generate:

    -
  • Commas separate components within one specification, such as -2,4,9, 0,2,5, or [100,-50].

  • -
  • Single spaces separate repeated specifications, such as -1,1,1 41,1,29 83,1,58 or [0,10000] [0,23000].

  • -
  • Two spaces separate free-text labels or titles when each value may -contain spaces, such as Reference case  Modified case.

  • -
  • Semicolons separate CSV column specifications for different inputs. -An empty specification skips the corresponding input, such as ;1,2,5.

  • -
  • Ampersands (``&``) join filter conditions for the same input.

  • -
  • Commas in ``-flt`` separate filter specifications for different -inputs.

  • -
  • Empty entries act as placeholders when an option applies only to -selected inputs.

  • +
  • two-dimensional maps of static and dynamic quantities;

  • +
  • summary plots and comparisons between simulation cases;

  • +
  • PNG figures and GIF animations;

  • +
  • CSV data for further analysis;

  • +
  • VTK files for three-dimensional visualization.

-

For example:

-
plopm -llb "Reference case  Modified case"
-plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5"
-plopm -i "table model" -v ",BWPR:256,1,5" -cc "1,3;"
-
-
-
-
-

Option reference

-

The options are grouped by purpose. Default values are also displayed by -plopm --help.

-
-

Note

-

Legacy option names from earlier plopm releases remain available for -backward compatibility. The documentation uses the preferred option names.

-
-
-

Input and data selection

-
-
-i, --input

Base name or full path of the input. Separate multiple inputs with spaces, -e.g., SPE11B /home/user/SPE11B_TUNED (SPE11B by default).

-
-
-v, --variable

Variable specification(s) to plot. Separate variables with commas, e.g., -pressure,sgas.

-

An empty entry may be used as a placeholder when the corresponding input -is configured through -cc, e.g.:

-
plopm -v ",BWPR:256,1,5" -cc "1,3;"
-
-
-

Special variables include grid, wells, faults, pcfact, -limipres, overpres, objepres, krw, krg, krow, -krog, pcow, pcog, pcwg, gasm, dism, liqm, -vapm, co2m, h2om, xco2l, xh2ov, xco2v, -xh2ol, fwcdm, and fgipm.

-

The default is -poro,permx,permz,porv,fipnum,satnum.

-
-
-r, --restart

Restart step(s), where 0 is the initial state and -1 is the last. -Separate selected steps with commas, e.g., 0,2 or 0,3,10,20, or -use start:end[:step], e.g., 1:3, 0:4:2, or 5:505:250.

-

The default is -1. GIF output uses all available steps by default.

-
-
-cc, --csv-columns

CSV column indices, starting at 1. Use t,value for a time series or -x,y,value for a spatial map.

-

Separate specifications for different inputs with semicolons. An empty -specification skips the corresponding input, e.g., ;1,2,5 or -1,3; (empty by default).

-
-
-fp, --flow-path

Path or command for the Flow executable, e.g., -/home/build/bin/flow. Used only to generate the grid for VTK output -(flow by default).

-
-
-
-
-

Output options

-
-
-m, --format

Output format: png, gif, csv, or vtk -(png by default).

-
-
-o, --output-dir

Base name or full path of the output directory. The default is ., -meaning the directory where plopm is executed.

-
-
-fn, --filename

Output file name. The default is empty, meaning that the name is set by -plopm.

-
-
-
-
-

Spatial and temporal selection

-
-
-s, --slice

Spatial selection in i,j,k form. An empty entry selects a plane, e.g., -10,,; a range projects over cells, e.g., ,,5:10; : selects a -line, e.g., :,5,7; and three indices select a cell over time, e.g., -2,4,9.

-

Separate multiple selections with spaces, e.g.:

-
plopm -s "1,1,1 41,1,29 83,1,58"
-
-
-

The default is ,1,.

-
-
-tu, --time-units

Summary-plot x-axis time units: s, m, h, d, w, y, -dates, empty, or tstep (d by default).

-
-
-dist, --distance

Compute the minimum or maximum distance to a sensor or lateral border. -Supported specifications are min,sensor, max,sensor, -min,border, and max,border.

-

For a sensor, provide its i,j,k location with -s, e.g.:

-
plopm -s 1,2,3 -v "sgas > 1e-2" -dist max,sensor
-
-
-

The default is empty, meaning that no distance is computed.

-
-
-
-
-

Filtering, masking, and thresholds

-
-
-flt, --filters

Cell-selection conditions. Join conditions for one input with & and -separate filters for different inputs with commas, e.g.:

-
plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5"
-
-
-

The default is empty. Dynamic variables such as sgas require RPORV -in RPTRST.

-
-
-vmin, --min-threshold

Minimum threshold used to remove variable values (empty by default).

-
-
-vmax, --max-threshold

Maximum threshold used to remove variable values (empty by default).

-
-
-mv, --mask-variable

Static variable used as the background of a 2D map (empty by default).

-
-
-mt, --mask-threshold

Threshold applied to the variable supplied through -mv -(1e-3 by default).

-
-
-
-
-

Computation and data transformation

-
-
-agg, --aggregation

Aggregation or selection method for 2D slices and projections. Supported -values are min, max, sum, mean, pvmean, harmonic, -arithmetic, first, and last.

-

Separate methods for multiple variables or plots with commas, e.g.:

-
plopm -agg "first,arithmetic,max"
+
+

Basic usage#

+

A typical command selects an input case, a variable, and a model slice:

+
plopm -i SPE11C -v pressure -s ,1,
 
-

By default, continuous variables are pore-volume weighted, extensive -quantities are summed, indices retain discrete values, and permeabilities -use directional harmonic or arithmetic averaging.

-

For wells and faults, min shows cells containing at least one -occurrence, while max requires all projected cells to contain one. -The default is empty, meaning that the method is selected automatically.

-
-
-sf, --scale-factor

Multiplicative scaling factor applied to variable values, e.g., 1e-9 -to display CO2 mass in Mt.

-

Separate factors for multiple variables or plots with commas, e.g., -1e-5,1 (1 by default).

-
-
-di, --difference-input

Base name or full path of the input model to subtract from the primary -input (empty by default).

-
-
-sc, --stress-coefficient

Stress coefficient used to compute pressure limits for limipres, -overpres, and objepres (0.134 by default).

-
-
-dg, --dual-grid

Enable dual-grid processing using 0 or 1 (0 by default).

-
-
+

This command plots pressure on the plane at j=1 and writes a PNG to the +current directory.

-
-

Plot types and statistical representation

-
-
-hist, --histogram

Histogram bins and optional distribution, e.g., 20, 20,norm, or -20,lognorm.

-

Separate specifications for multiple plots with spaces, e.g.:

-
plopm -hist "50,norm 20,lognorm 100"
-
-
-

The default is empty, meaning that no histogram is plotted.

-
-
-ens, --ensemble

Ensemble plotting mode:

+
+

Where to continue#

    -
  • 0 disables ensemble plotting.

  • -
  • 1 plots the mean and error bands.

  • -
  • 2 plots the minimum, mean, and maximum.

  • -
  • 3 plots both representations.

  • +
  • See Installation to install plopm and its optional dependencies.

  • +
  • Follow the Tutorial to progress from a first PNG to projections, +comparisons, animations, and data export.

  • +
  • Browse the Examples for complete visualization recipes.

  • +
  • Use the Command-line reference for syntax and option descriptions.

  • +
  • See the Python API to use plopm from Python.

  • +
  • See Contributing to report issues, request features, or contribute to +plopm.

  • +
  • Explore Related projects for complementary open-source tools.

-

The default is 0.

-
-
-fb, --fill-between-style

Fill colors and alpha values used for ensemble error bands, supplied as -comma-separated pairs, e.g., r,0.1,g,0.2.

-

This option is used with -ens 1 or -ens 3. The default is empty, -meaning that the mean color is used with an alpha value of 0.2.

-
-
-sp, --step-plot

Use ax.step instead of ax.plot: 0 or 1 -(0 by default).

-
-
-
-
-

Figure and subplot layout

-
-
-fs, --figsize

Figure width and height in inches, separated by a comma, e.g., 8,16 -(7,5 by default).

-
-
-sg, --subplot-grid

Number of subplot rows and columns, separated by a comma, e.g., 2,2 -for four subplots.

-

The default is empty, meaning that separate figures are created.

-
-
-cbp, --colorbar-position

Global colorbar position and size as left,bottom,width,height, e.g., -0.1,0.95,0.8,0.02.

-

Use empty to remove the global colorbar. The default is -0.2,0.01,0.6,0.02.

-
-
-rdl, --remove-duplicate-labels

Remove duplicated axis labels in subplot layouts using 0 or 1 -(0 by default).

-
-
-
-

Titles, labels, and legends

-
-
-t, --title

Figure title. Separate titles for multiple plots with two spaces -(0 by default).

-

For example:

-
plopm -t "Reference case  Modified case"
-
-
-
-
-st, --suptitle

Title for a group of subplots. Use 0 to remove it. The default is -empty, meaning that the title is set by plopm.

-
-
-xl, --xlabel

X-axis label. Separate labels for multiple plots with two spaces. The -default is empty, meaning that labels are set by plopm.

-
-
-yl, --ylabel

Y-axis label. Separate labels for multiple plots with two spaces. The -default is empty, meaning that labels are set by plopm.

-
-
-cbl, --colorbar-label

Colorbar label. Separate labels for multiple plots with two spaces. The -default is empty, meaning that labels are set by plopm.

-
-
-llb, --legend-labels

Summary-plot legend labels. Separate labels with two spaces, e.g.:

-
plopm -llb "Reference case  Modified case"
-
-
-

The default is empty, meaning that labels are set by plopm.

-
-
-ll, --legend-location

Legend location passed to matplotlib.pyplot.legend. Supported values -are best, upper right, upper left, lower left, -lower right, right, center left, center right, -lower center, upper center, and center.

-

Use empty to remove the legend (best by default).

-
-
-hide, --hide-map-elements

Hide the left axis, bottom axis, colorbar, and title using four -comma-separated values of 0 or 1, in that order.

-

For example, 1,0,1,0 hides the left axis and colorbar while retaining -the bottom axis and title. The default is 0,0,0,0.

-
-
+
+

About the project#

+

plopm is funded by the HPC Simulation Software for the Gigatonne +Storage Challenge project +(project number 622059) and the Center for Sustainable Subsurface Resources (project number 331841).

+

Contributions are welcome. See Contributing to propose changes or +open an issue to +report a problem or request a feature.

-
-

Axes, coordinates, and formatting

-
-
-x, --xlim

X-axis limits in the requested display order, e.g., [-100,200] or -[200,-100].

-

Separate limits for multiple plots with spaces, e.g.:

-
plopm -x "[-100,200] [500,0]"
-
-
-

The default is empty.

-
-
-y, --ylim

Y-axis limits in the requested display order, e.g., [0,70] or -[70,0].

-

Separate limits for multiple plots with spaces, e.g.:

-
plopm -y "[0,10000] [0,23000]"
-
-
-

The default is empty.

-
-
-xu, --xunits

Spatial-map x-axis units: mm, cm, m, or km -(m by default).

-
-
-yu, --yunits

Spatial-map y-axis units: mm, cm, m, or km -(m by default).

-
-
-asp, --equal-aspect

Scale the axes equally in 2D maps using 0 or 1 -(1 by default).

-
-
-rot, --rotation

Grid rotation angle in degrees for 2D maps (0 by default).

-
-
-tr, --translation

Grid translation in the x and y directions, e.g., [100,-50] -([0,0] by default).

-
-
-xlog, --xlog

Enable the logarithmic x-axis using 0 or 1.

-

Comma-separated settings are accepted when different plots require -different values (0 by default).

-
-
-ylog, --ylog

Enable the logarithmic y-axis using 0 or 1.

-

Comma-separated settings are accepted when different plots require -different values (0 by default).

-
-
-xf, --xformat

X-axis number format, e.g., .2e. The default is empty, meaning that -the format is set by plopm.

-
-
-yf, --yformat

Y-axis number format, e.g., .1f. The default is empty, meaning that -the format is set by plopm.

-
-
-xnt, --xtick-count

Number of x-axis ticks (5 by default).

-
-
-ynt, --ytick-count

Number of y-axis ticks (5 by default).

-
-
-
-

Color scales and styling

-
-
-c, --colors

Colormap for spatial plots, e.g., jet, or summary-plot colors -separated by commas, e.g., b,r.

-

The default is empty, meaning that colors are selected by plopm.

-
-
-cl, --clim

Color-scale limits in the requested display order, e.g., [-0.1,11] or -[11,-0.1].

-

Separate limits for multiple plots with spaces. The default is empty.

-
-
-clog, --color-log

Enable logarithmic color scaling using 0 or 1.

-

Separate settings for multiple variables with commas, e.g.:

-
plopm -clog "1,1,0"
-
+ + +
+ + + + + +
+ + -

The default is 0.

- -
-clt, --color-log-ticks

Tick values for logarithmic color scales, enclosed by brackets and -separated by commas, e.g., [1,10,100].

-

At least one corresponding -clog setting must be 1. The default -is empty.

-
-
-gr, --global-range

Use the value range of the current slice or the entire 3D model for color -scaling:

-
    -
  • 0 uses the current slice range.

  • -
  • 1 uses the whole-model range.

  • +
+ +
+ + + + +
+ +
+ +
-
- -
- -
-

© Copyright 2024-2026, NORCE Research AS.

+ + + + - Built with Sphinx using a - theme - provided by Read the Docs. - +
+
- - - - - + + + + + + + + + + - +
+ \ No newline at end of file diff --git a/docs/modules.html b/docs/modules.html deleted file mode 100644 index 92b332d..0000000 --- a/docs/modules.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - plopm — plopm documentation - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
- -
- -
- -
-

© Copyright 2024-2026, NORCE Research AS.

-
- - Built with Sphinx using a - theme - provided by Read the Docs. - - -
-
-
-
-
- - - - \ No newline at end of file diff --git a/docs/objects.inv b/docs/objects.inv index 6be2b8c..4bc2428 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/options/axes.html b/docs/options/axes.html new file mode 100644 index 0000000..e78d0cf --- /dev/null +++ b/docs/options/axes.html @@ -0,0 +1,701 @@ + + + + + + + + + + + Axes, coordinates, and formatting — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Axes, coordinates, and formatting#

+

Control limits, units, transformations, logarithmic axes, formats, and ticks.

+
+

-x/--xlim <LIMITS>#

+

Set x-axis limits in the requested display order, for example [-100,200] or [200,-100].

+

Separate limits for multiple plots with spaces:

+
plopm -x "[-100,200] [500,0]"
+
+
+

Default: empty

+
+
+

-y/--ylim <LIMITS>#

+

Set y-axis limits in the requested display order, for example [0,70] or [70,0].

+

Separate limits for multiple plots with spaces:

+
plopm -y "[0,10000] [0,23000]"
+
+
+

Default: empty

+
+
+

-xu/--xunits <UNITS>#

+

Set spatial-map x-axis units to mm, cm, m, or km.

+

Default: m

+
+
+

-yu/--yunits <UNITS>#

+

Set spatial-map y-axis units to mm, cm, m, or km.

+

Default: m

+
+
+

-asp/--equal-aspect <0|1>#

+

Scale the axes equally in two-dimensional maps when set to 1.

+

Default: 1

+
+
+

-rot/--rotation <DEGREES>#

+

Set the grid rotation angle in degrees for two-dimensional maps.

+

Default: 0

+
+
+

-tr/--translation <X,Y>#

+

Set grid translation in the x and y directions, for example [100,-50].

+

Default: [0,0]

+
+
+

-xlog/--xlog <0|1>#

+

Enable a logarithmic x-axis with 1. Comma-separated settings are accepted when plots require different values.

+

Default: 0

+
+
+

-ylog/--ylog <0|1>#

+

Enable a logarithmic y-axis with 1. Comma-separated settings are accepted when plots require different values.

+

Default: 0

+
+
+

-xf/--xformat <FORMAT>#

+

Set the x-axis number format, for example .2e.

+

Default: empty, so plopm selects the format.

+
+
+

-yf/--yformat <FORMAT>#

+

Set the y-axis number format, for example .1f.

+

Default: empty, so plopm selects the format.

+
+
+

-xnt/--xtick-count <COUNT>#

+

Set the number of x-axis ticks.

+

Default: 5

+
+
+

-ynt/--ytick-count <COUNT>#

+

Set the number of y-axis ticks.

+

Default: 5

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/computation.html b/docs/options/computation.html new file mode 100644 index 0000000..a941489 --- /dev/null +++ b/docs/options/computation.html @@ -0,0 +1,653 @@ + + + + + + + + + + + Computation and data transformation — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Computation and data transformation#

+

Aggregate, scale, compare, and transform simulation quantities.

+
+

-agg/--aggregation <METHODS>#

+

Set aggregation or selection methods for two-dimensional slices and projections. Supported values are min, max, sum, mean, pvmean, harmonic, arithmetic, first, and last.

+

Separate methods for multiple variables or plots with commas:

+
plopm -agg "first,arithmetic,max"
+
+
+

By default, continuous variables are pore-volume weighted, extensive quantities are summed, indices retain discrete values, and permeabilities use directional harmonic or arithmetic averaging.

+

For wells and faults, min shows cells containing at least one occurrence, while max requires all projected cells to contain one.

+

Default: empty, so plopm selects the method automatically.

+

See Project and average quantities for a guided workflow.

+
+
+

-sf/--scale-factor <FACTORS>#

+

Multiply variable values by a scaling factor, for example 1e-9 to display CO2 mass in Mt.

+

Separate factors for multiple variables or plots with commas, for example 1e-5,1.

+

Default: 1

+
+
+

-di/--difference-input <INPUT>#

+

Set the base name or full path of the input model to subtract from the primary input.

+

Default: empty

+
+
+

-sc/--stress-coefficient <VALUE>#

+

Set the stress coefficient used to compute pressure limits for limipres, overpres, and objepres.

+

Default: 0.134

+
+
+

-dg/--dual-grid <0|1>#

+

Enable dual-grid processing with 1 and disable it with 0.

+

Default: 0

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/diagnostics.html b/docs/options/diagnostics.html new file mode 100644 index 0000000..885b7af --- /dev/null +++ b/docs/options/diagnostics.html @@ -0,0 +1,621 @@ + + + + + + + + + + + Information and diagnostics — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Information and diagnostics#

+

Inspect the variables available for an input case.

+
+

-lv/--list-variables <0|1>#

+

Print the available variables when set to 1.

+

Default: 0

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/filtering.html b/docs/options/filtering.html new file mode 100644 index 0000000..b528b0e --- /dev/null +++ b/docs/options/filtering.html @@ -0,0 +1,649 @@ + + + + + + + + + + + Filtering, masking, and thresholds — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Filtering, masking, and thresholds#

+

Filter cells, remove values, and add a static map mask.

+
+

-flt/--filters <CONDITIONS>#

+

Set cell-selection conditions. Join conditions for one input with & and separate filters for different inputs with commas:

+
plopm -flt "fluxnum == 2 & sgas >= 0.2, satnum != 5"
+
+
+

Dynamic variables such as sgas require RPORV in RPTRST.

+

Default: empty

+
+
+

-vmin/--min-threshold <VALUE>#

+

Remove variable values below the minimum threshold.

+

Default: empty

+
+
+

-vmax/--max-threshold <VALUE>#

+

Remove variable values above the maximum threshold.

+

Default: empty

+
+
+

-mv/--mask-variable <VARIABLE>#

+

Use a static variable as the background of a two-dimensional map.

+

Default: empty

+
+
+

-mt/--mask-threshold <VALUE>#

+

Set the threshold applied to the variable supplied through plopm -mv.

+

Default: 1e-3

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/gif.html b/docs/options/gif.html new file mode 100644 index 0000000..8ec5943 --- /dev/null +++ b/docs/options/gif.html @@ -0,0 +1,627 @@ + + + + + + + + + + + GIF output — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

GIF output#

+

These options apply only when -m gif is selected.

+
+

-gi/--gif-interval <MILLISECONDS>#

+

Set the GIF frame interval in milliseconds.

+

Default: 1000

+
+
+

-gl/--gif-loop <0|1>#

+

Loop GIF animations indefinitely when set to 1.

+

Default: 0

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/input-data.html b/docs/options/input-data.html new file mode 100644 index 0000000..dd25e12 --- /dev/null +++ b/docs/options/input-data.html @@ -0,0 +1,652 @@ + + + + + + + + + + + Input and data selection — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Input and data selection#

+

Select simulation inputs, variables, restart steps, CSV columns, and the Flow executable.

+
+

-i/--input <INPUT>#

+

Set the base name or full path of the input. Separate multiple inputs with spaces, for example SPE11B /home/user/SPE11B_TUNED.

+

Default: SPE11B

+
+
+

-v/--variable <VARIABLES>#

+

Select the variables to plot. Separate variables with commas, for example pressure,sgas.

+

An empty entry can act as a placeholder when the corresponding input is configured with plopm -cc:

+
plopm -v ",BWPR:256,1,5" -cc "1,3;"
+
+
+

Special variables include grid, wells, faults, pcfact, limipres, overpres, objepres, krw, krg, krow, krog, pcow, pcog, pcwg, gasm, dism, liqm, vapm, co2m, h2om, xco2l, xh2ov, xco2v, xh2ol, fwcdm, and fgipm.

+

Default: poro,permx,permz,porv,fipnum,satnum

+
+
+

-r/--restart <STEPS>#

+

Select restart steps. 0 is the initial state and -1 is the last state. Separate selected steps with commas, for example 0,2 or 0,3,10,20, or use start:end[:step], for example 1:3, 0:4:2, or 5:505:250.

+

GIF output uses all available steps when this option is omitted.

+

Default: -1

+
+
+

-cc/--csv-columns <COLUMNS>#

+

Set CSV column indices, starting at 1. Use t,value for a time series or x,y,value for a spatial map.

+

Separate specifications for different inputs with semicolons. An empty specification skips the corresponding input, for example ;1,2,5 or 1,3;.

+

Default: empty

+
+
+

-fp/--flow-path <COMMAND>#

+

Set the path or command for the Flow executable, for example /home/build/bin/flow. This is used only to generate the grid for VTK output.

+

Default: flow

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/layout.html b/docs/options/layout.html new file mode 100644 index 0000000..a9ca5e6 --- /dev/null +++ b/docs/options/layout.html @@ -0,0 +1,640 @@ + + + + + + + + + + + Figure and subplot layout — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Figure and subplot layout#

+

Set figure dimensions, subplot layout, and the global colorbar.

+
+

-fs/--figsize <WIDTH,HEIGHT>#

+

Set the figure width and height in inches, separated by a comma, for example 8,16.

+

Default: 7,5

+
+
+

-sg/--subplot-grid <ROWS,COLUMNS>#

+

Set the number of subplot rows and columns, separated by a comma, for example 2,2 for four subplots.

+

Default: empty, so separate figures are created.

+
+
+

-cbp/--colorbar-position <LEFT,BOTTOM,WIDTH,HEIGHT>#

+

Set the global colorbar position and size as left,bottom,width,height, for example 0.1,0.95,0.8,0.02.

+

Use empty to remove the global colorbar.

+

Default: 0.2,0.01,0.6,0.02

+
+
+

-rdl/--remove-duplicate-labels <0|1>#

+

Remove duplicated axis labels in subplot layouts when set to 1.

+

Default: 0

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/output.html b/docs/options/output.html new file mode 100644 index 0000000..ae70f73 --- /dev/null +++ b/docs/options/output.html @@ -0,0 +1,633 @@ + + + + + + + + + + + Output options — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Output options#

+

Choose the output format, directory, and filename.

+
+

-m/--format <FORMAT>#

+

Select the output format: png, gif, csv, or vtk.

+

Default: png

+
+
+

-o/--output-dir <DIRECTORY>#

+

Set the base name or full path of the output directory.

+

Default: ., the directory where plopm is executed.

+
+
+

-fn/--filename <NAME>#

+

Set the output filename.

+

Default: empty, so plopm generates the name.

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/plot-types.html b/docs/options/plot-types.html new file mode 100644 index 0000000..ba6f92a --- /dev/null +++ b/docs/options/plot-types.html @@ -0,0 +1,650 @@ + + + + + + + + + + + Plot types and statistical representation — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Plot types and statistical representation#

+

Create histograms, ensemble statistics, and step-style summary plots.

+
+

-hist/--histogram <SPECIFICATION>#

+

Set histogram bins and an optional distribution, for example 20, 20,norm, or 20,lognorm.

+

Separate specifications for multiple plots with spaces:

+
plopm -hist "50,norm 20,lognorm 100"
+
+
+

Default: empty, so no histogram is plotted.

+
+
+

-ens/--ensemble <MODE>#

+

Set the ensemble plotting mode:

+
    +
  • 0 disables ensemble plotting.

  • +
  • 1 plots the mean and error bands.

  • +
  • 2 plots the minimum, mean, and maximum.

  • +
  • 3 plots both representations.

  • +
+

Default: 0

+
+
+

-fb/--fill-between-style <STYLE>#

+

Set fill colors and alpha values for ensemble error bands as comma-separated pairs, for example r,0.1,g,0.2.

+

Use this option with -ens 1 or -ens 3.

+

Default: empty, so the mean color is used with an alpha value of 0.2.

+
+
+

-sp/--step-plot <0|1>#

+

Use ax.step instead of ax.plot when set to 1.

+

Default: 0

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/selection.html b/docs/options/selection.html new file mode 100644 index 0000000..bbfcac2 --- /dev/null +++ b/docs/options/selection.html @@ -0,0 +1,642 @@ + + + + + + + + + + + Spatial and temporal selection — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Spatial and temporal selection#

+

Select model locations and summary-plot time units.

+
+

-s/--slice <I,J,K>#

+

Set a spatial selection in i,j,k form. An empty entry selects a plane, for example 10,,; a range projects over cells, for example ,,5:10; : selects a line, for example :,5,7; and three indices select a cell over time, for example 2,4,9.

+

Separate multiple selections with spaces:

+
plopm -s "1,1,1 41,1,29 83,1,58"
+
+
+

Default: ,1,

+

See Slice the three-dimensional model for a guided workflow.

+
+
+

-tu/--time-units <UNITS>#

+

Set summary-plot x-axis time units. Accepted values are s, m, h, d, w, y, dates, empty, and tstep.

+

Default: d

+
+
+

-dist/--distance <MODE>#

+

Compute the minimum or maximum distance to a sensor or lateral border. Accepted values are min,sensor, max,sensor, min,border, and max,border.

+

For a sensor, provide its i,j,k location with plopm -s:

+
plopm -s 1,2,3 -v "sgas > 1e-2" -dist max,sensor
+
+
+

Default: empty, so no distance is computed.

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/styling.html b/docs/options/styling.html new file mode 100644 index 0000000..993357c --- /dev/null +++ b/docs/options/styling.html @@ -0,0 +1,718 @@ + + + + + + + + + + + Color scales and styling — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Color scales and styling#

+

Control colors, colorbars, lines, grids, map appearance, fonts, and resolution.

+
+

-c/--colors <COLORS>#

+

Set the colormap for spatial plots, for example jet, or summary-plot colors separated by commas, for example b,r.

+

Default: empty, so plopm selects the colors.

+
+
+

-cl/--clim <LIMITS>#

+

Set color-scale limits in the requested display order, for example [-0.1,11] or [11,-0.1]. Separate limits for multiple plots with spaces.

+

Default: empty

+
+
+

-clog/--color-log <0|1>#

+

Enable logarithmic color scaling with 1. Separate settings for multiple variables with commas:

+
plopm -clog "1,1,0"
+
+
+

Default: 0

+
+
+

-clt/--color-log-ticks <TICKS>#

+

Set logarithmic color-scale ticks in brackets, separated by commas, for example [1,10,100]. At least one corresponding plopm -clog setting must be 1.

+

Default: empty

+
+
+

-gr/--global-range <0|1>#

+

Select the values used for color scaling:

+
    +
  • 0 uses the current slice range.

  • +
  • 1 uses the whole-model range.

  • +
+

Default: 0

+
+
+

-cbf/--colorbar-format <FORMAT>#

+

Set the colorbar number format, for example .2f.

+

Default: empty, so plopm selects the format.

+
+
+

-cbn/--colorbar-tick-count <COUNT>#

+

Set the number of colorbar ticks. Separate values for multiple plots with commas, for example 3,6,2.

+

Default: empty, so plopm selects the number of ticks.

+
+
+

-cbt/--colorbar-ticks <LABELS>#

+

Set custom colorbar tick labels in brackets, separated by commas, for example [G,F,E,D,C,ESF].

+

Default: empty

+
+
+

-lw/--linewidth <WIDTHS>#

+

Set line widths separated by commas, for example 1,2,1.5.

+

Default: empty, so plopm selects the widths.

+
+
+

-ls/--linestyle <STYLES>#

+

Set line styles separated by commas, for example solid,dotted.

+

Default: empty, so plopm selects the styles.

+
+
+

-ag/--axis-grid <0|1>#

+

Display the summary-plot axis grid when set to 1.

+

Default: 1

+
+
+

-fc/--facecolor <COLOR>#

+

Set the color outside the spatial map.

+

Default: w (white)

+
+
+

-ic/--inactive-color <COLOR>#

+

Set the color of inactive cells in two-dimensional maps.

+

Default: w (white)

+
+
+

-ge/--grid-edges <COLOR,WIDTH>#

+

Set the pcolormesh edge color and line width, for example black,1e-3.

+

Default: empty, so cell edges are not displayed.

+
+
+

-fz/--fontsize <SIZE>#

+

Set the font size.

+

Default: 12

+
+
+

-dpi/--dpi <VALUE>#

+

Set figure resolution in dots per inch.

+

Default: 500

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/syntax.html b/docs/options/syntax.html new file mode 100644 index 0000000..b0b93b1 --- /dev/null +++ b/docs/options/syntax.html @@ -0,0 +1,749 @@ + + + + + + + + + + + Syntax and conventions — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Syntax and conventions#

+

A plopm command selects input data, variables, and an output:

+
plopm -i INPUT -v VARIABLES [OPTIONS]
+
+
+

For example:

+
plopm -i SPE11C -v pressure -s ,1, -r 5
+
+
+

Use plopm --help for the options supported by the installed version.

+
+

Canonical option names#

+

Each option has a short and a long canonical name:

+
plopm -i SPE11C -v pressure
+plopm --input SPE11C --variable pressure
+
+
+

Commands in this documentation use the short canonical names. The category +pages show both forms.

+
+
+

Paths and quoting#

+

Quote paths and values that contain spaces:

+
plopm -i "/path/to/my case/SPE11C" -v pressure
+
+
+
+
+

Multiple inputs#

+

Separate input cases with spaces and quote the complete value:

+
plopm -i "SPE11C SPE11C_TUNED" -v pressure
+
+
+

See plopm -i.

+
+
+

Multiple variables#

+

Separate variables with commas:

+
plopm -i SPE11C -v pressure,sgas
+
+
+

See plopm -v.

+
+
+

Expressions#

+

Quote expressions containing spaces:

+
plopm -i SPE11C -v "pressure - 0pressure"
+
+
+

See plopm -v.

+
+
+

Spatial selections#

+

The spatial selection uses three comma-separated positions:

+
I,J,K
+
+
+

Select the plane at j=10:

+
plopm -i SPE11C -v pressure -s ,10,
+
+
+

Select layers 5 through 10:

+
plopm -i SPE11C -v pressure -s ,,5:10
+
+
+

See plopm -s and Slice the three-dimensional model.

+
+
+

Restart steps#

+

Select one restart step:

+
plopm -i SPE11C -v pressure -r 5
+
+
+

Select several steps:

+
plopm -i SPE11C -v pressure -r 0,3,10
+
+
+

Select a range using start:end[:step]:

+
plopm -i SPE11C -v pressure -r 5:505:250
+
+
+

See plopm -r.

+
+
+

Aggregation#

+

Select a range with -s and apply an aggregation method with -agg:

+
plopm -i SPE11C -v pressure -s ,,5:10 -agg mean -r 5
+
+
+

Supported methods are min, max, sum, mean, pvmean, +harmonic, arithmetic, first, and last.

+

See plopm -agg and Project and average quantities.

+
+
+

Text for multiple plots#

+

Some title and label options use two spaces to separate text for different +plots. Quote the complete value:

+
plopm -i SPE11C -v pressure,sgas -sg 1,2 -t "Pressure  Gas saturation"
+
+
+

See plopm -t and plopm -sg.

+
+
+

Output formats#

+

Use -m to select PNG, GIF, CSV, or VTK output:

+
plopm -i SPE11C -v pressure -m png
+plopm -i SPE11C -v pressure -m gif
+plopm -i SPE11C -v pressure -m csv
+plopm -i SPE11C -m vtk
+
+
+

See plopm -m.

+
+
+

Getting help#

+

Display the built-in help:

+
plopm --help
+
+
+

Print the variables available for an input case:

+
plopm -i SPE11C -lv 1
+
+
+

See plopm -lv.

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/titles-labels.html b/docs/options/titles-labels.html new file mode 100644 index 0000000..f6f856e --- /dev/null +++ b/docs/options/titles-labels.html @@ -0,0 +1,671 @@ + + + + + + + + + + + Titles, labels, and legends — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

Titles, labels, and legends#

+

Set titles, labels, legends, and the visibility of map elements.

+
+

-t/--title <TITLE>#

+

Set the figure title. Separate titles for multiple plots with two spaces:

+
plopm -t "Reference case  Modified case"
+
+
+

Default: 0

+
+
+

-st/--suptitle <TITLE>#

+

Set the title for a group of subplots. Use 0 to remove it.

+

Default: empty, so plopm sets the title.

+
+
+

-xl/--xlabel <LABEL>#

+

Set the x-axis label. Separate labels for multiple plots with two spaces.

+

Default: empty, so plopm sets the labels.

+
+
+

-yl/--ylabel <LABEL>#

+

Set the y-axis label. Separate labels for multiple plots with two spaces.

+

Default: empty, so plopm sets the labels.

+
+
+

-cbl/--colorbar-label <LABEL>#

+

Set the colorbar label. Separate labels for multiple plots with two spaces.

+

Default: empty, so plopm sets the labels.

+
+
+

-llb/--legend-labels <LABELS>#

+

Set summary-plot legend labels. Separate labels with two spaces:

+
plopm -llb "Reference case  Modified case"
+
+
+

Default: empty, so plopm sets the labels.

+
+
+

-ll/--legend-location <LOCATION>#

+

Set the legend location passed to matplotlib.pyplot.legend. Accepted values are best, upper right, upper left, lower left, lower right, right, center left, center right, lower center, upper center, and center.

+

Use empty to remove the legend.

+

Default: best

+
+
+

-hide/--hide-map-elements <LEFT,BOTTOM,COLORBAR,TITLE>#

+

Hide the left axis, bottom axis, colorbar, and title using four comma-separated 0 or 1 values in that order.

+

For example, 1,0,1,0 hides the left axis and colorbar while retaining the bottom axis and title.

+

Default: 0,0,0,0

+
+
+ + +
+ + + + + + + +
+ + + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/options/vtk.html b/docs/options/vtk.html new file mode 100644 index 0000000..ab4bb9e --- /dev/null +++ b/docs/options/vtk.html @@ -0,0 +1,628 @@ + + + + + + + + + + + VTK output — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+

VTK output#

+

These options apply only when -m vtk is selected.

+
+

-vf/--vtk-format <FORMATS>#

+

Set the VTK data type for each variable. Supported formats are Float64, Float32, Float16, Int64, UInt64, Int32, UInt32, Int16, UInt16, Int8, and UInt8.

+

Separate formats for multiple variables with commas.

+

Default: Float64

+
+
+

-vn/--vtk-names <NAMES>#

+

Set custom VTK variable names separated by commas.

+

Default: empty, so the names supplied through plopm -v are used.

+
+
+ + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/plopm.config.config.html b/docs/plopm.config.config.html deleted file mode 100644 index f3cde7b..0000000 --- a/docs/plopm.config.config.html +++ /dev/null @@ -1,946 +0,0 @@ - - - - - - - - - plopm.config.config module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.config.config module

-

Configuration and simulation-data models shared across plopm workflows.

-

PlopmConfig stores command-line options and normalized runtime settings used to -create summary plots, spatial maps, animations, and VTK output. SimData stores -OPM file handles, grid dimensions, and cell data loaded for one simulation case.

-

Both objects are mutable because CLI values are normalized and simulation data -are populated progressively during processing.

-
-
-class plopm.config.config.PlopmConfig(gif: bool = False, csv: bool = False, png: bool = False, vtk: bool = False, equal_aspect: bool = False, remove_duplicate_labels: bool = False, list_variables: bool = False, gif_loop: bool = False, step_plot: bool = False, global_range: bool = False, rst_range: bool = False, sensor: bool = False, layer: bool = False, csv_column_summary: bool = False, discrete: bool = True, fontsize: float = 0.0, mask_threshold: float = 0.0, gif_interval: float = 0.0, stress_coefficient: float = 0.0, xscale: float = 1.0, yscale: float = 1.0, ensemble: int = 0, ncolors: int = 1, color_log_ticks: list = <factory>, case_labels: list = <factory>, cases: list = <factory>, dual_grid: list = <factory>, subplot_grid: list = <factory>, variables: list = <factory>, filters: list = <factory>, title: list = <factory>, clim: list = <factory>, figsize: list = <factory>, min_threshold: list = <factory>, max_threshold: list = <factory>, grid_edges: list = <factory>, colorbar_tick_count: list = <factory>, legend_labels: list = <factory>, hide_map_elements: list = <factory>, time_units: list = <factory>, scale_factor: list = <factory>, axis_grid: list = <factory>, dpi: list = <factory>, colorbar_ticks: list = <factory>, legend_location: list = <factory>, vtk_format: list = <factory>, vtk_names: list = <factory>, color_log: list = <factory>, rotation: list = <factory>, filename: list = <factory>, translation: list = <factory>, restart: list = <factory>, aggregation: list = <factory>, distance: list = <factory>, histogram: list = <factory>, xlabel: list = <factory>, xformat: list = <factory>, xtick_count: list = <factory>, xlog: list = <factory>, xlim: list = <factory>, ylabel: list = <factory>, yformat: list = <factory>, ytick_count: list = <factory>, ylog: list = <factory>, ylim: list = <factory>, vsum: list = <factory>, summary: list = <factory>, time: list = <factory>, wells: list = <factory>, faults: list = <factory>, slice: list = <factory>, csv_columns: list = <factory>, mass_vars: list = <factory>, summary_mass: list = <factory>, mass_fracs: list = <factory>, caprock_vars: list = <factory>, linewidth_values: list = <factory>, units: list = <factory>, cb_formats: list = <factory>, colormaps: list = <factory>, disc_colormaps: list = <factory>, linestyle: list = <factory>, linewidth: list = <factory>, colors: list = <factory>, colors_default: list = <factory>, linestyle_default: list = <factory>, colorbar_position: tuple[float, float, float, float]=(-1.0, -1.0, -1.0, -1.0), difference_input: str = '', colors_raw: str = '', output_dir: str = '', case: str = '', fill_between_style: str = '', colorbar_format: str = '', fc: str = '', inactive_color: str = '', mask_variable: str = '', suptitle: str = '', colorbar_label: str = '', slice_mode: str = '', xunits: str = '', yunits: str = '', xunit: str = '', yunit: str = '')
-

Bases: object

-

Options and runtime settings for a plopm operation.

-

Most list fields contain one value per variable, case, or subplot after -initialization. Values read from the CLI are normalized before plotting so -downstream functions can use consistent indexing.

-
-
Attributes:
-
-
gif, csv, png, vtk

Whether GIF, CSV, PNG, or VTK output is active for the current run.

-
-
equal_aspect

Whether spatial maps use the same scale along both coordinate axes.

-
-
remove_duplicate_labels

Whether repeated axis labels are hidden in subplot layouts.

-
-
list_variables

Whether available INIT, UNRST, and summary variables are printed.

-
-
gif_loop

Whether generated GIF animations repeat after the final frame.

-
-
step_plot

Whether one-dimensional series are drawn as step plots.

-
-
global_range

Whether map limits and features are evaluated globally instead of only -within the selected slice.

-
-
rst_range

Whether PNG color limits are evaluated over the restart range.

-
-
sensor

Whether one-dimensional values are extracted at a grid-cell sensor.

-
-
layer

Whether one-dimensional values are extracted along a grid axis or layer.

-
-
csv_column_summary

Whether a one-dimensional series is read from CSV columns.

-
-
discrete

Whether the current spatial quantity uses discrete color categories.

-
-
fontsize

Base font size used in generated figures.

-
-
mask_threshold

Threshold applied to the selected mask variable.

-
-
gif_interval

Delay between GIF frames.

-
-
stress_coefficient

Vertical stress coefficient used for caprock-integrity quantities.

-
-
xscale, yscale

Factors converting grid coordinates to the requested spatial units.

-
-
ensemble

Ensemble mode controlling uncertainty bands and bounding members.

-
-
ncolors

Number of case-dependent styles used for summary plots.

-
-
color_log_ticks

Tick values used on logarithmic colorbars.

-
-
case_labels

User-provided case names used in legends and ensemble labels.

-
-
cases

Simulation-case paths grouped as requested by the CLI.

-
-
dual_grid

Per-variable flags enabling dual-porosity grid handling.

-
-
subplot_grid

Requested subplot rows and columns.

-
-
variables

Variables or variable expressions requested for processing.

-
-
filters

Property-filter expressions applied per case or variable.

-
-
title

Per-plot titles.

-
-
clim

Lower and upper color limits for spatial maps.

-
-
figsize

Figure width and height for each generated plot.

-
-
min_threshold, max_threshold

Limits outside which quantity values are hidden.

-
-
grid_edges

Per-map settings controlling cell-edge drawing.

-
-
colorbar_tick_count

Requested number of colorbar ticks.

-
-
legend_labels

Labels for cases, variables, or ensemble bounds.

-
-
hide_map_elements

Map components to omit, such as axes, labels, or colorbars.

-
-
time_units

Requested time unit for each one-dimensional plot.

-
-
scale_factor

Multipliers applied to plotted or exported quantity values.

-
-
axis_grid

Per-plot settings controlling the Matplotlib axis grid.

-
-
dpi

Output resolution for each generated figure.

-
-
colorbar_ticks

Explicit colorbar tick values.

-
-
legend_location

Per-plot legend placement.

-
-
vtk_format

VTK data type selected for each exported variable.

-
-
vtk_names

Variable names written to VTK cell-data arrays.

-
-
color_log

Flags selecting logarithmic color normalization.

-
-
rotation

Rotation angles applied to grid coordinates, in degrees.

-
-
filename

Output filenames normalized per requested plot.

-
-
translation

Coordinate translations applied after rotation.

-
-
restart

Selected OPM restart report steps.

-
-
aggregation

Aggregation method applied through a slice or selected cells.

-
-
distance

Distance method and target, such as a sensor or model boundaries.

-
-
histogram

Histogram settings, including the requested bins.

-
-
xlabel, ylabel

Per-plot axis labels.

-
-
xformat, yformat

Format strings used for axis tick labels.

-
-
xtick_count, ytick_count

Requested numbers of major ticks.

-
-
xlog, ylog

Flags selecting logarithmic axes.

-
-
xlim, ylim

Per-plot axis limits.

-
-
vsum

Summary-variable expressions prepared for plotting.

-
-
summary

Loaded or derived summary-series values.

-
-
time

Time coordinates associated with summary values.

-
-
wells, faults

Parsed feature locations used in spatial maps.

-
-
slice

Parsed i, j, and k selections used by all workflows.

-
-
csv_columns

CSV column settings retained in parsed per-plot form.

-
-
mass_vars

Supported component-mass quantities.

-
-
summary_mass

Summary vectors converted from standard volume to mass.

-
-
mass_fracs

Supported component mass-fraction quantities.

-
-
caprock_vars

Supported caprock-integrity quantities.

-
-
linewidth_values

Default line widths before per-variable normalization.

-
-
units

Display units associated with requested quantities.

-
-
cb_formats

Normalized numeric formats used for colorbar labels.

-
-
colormaps

Colormaps assigned to spatial variables.

-
-
disc_colormaps

Available colormaps suitable for discrete values.

-
-
linestyle, linewidth, colors

Normalized styles used by summary plots.

-
-
colors_default, linestyle_default

Default style sequences used when none are supplied.

-
-
colorbar_position

Relative position and size of an explicitly placed colorbar axis.

-
-
difference_input

Second case, folder, or file used to calculate differences.

-
-
colors_raw

Color specification received from the CLI before normalization.

-
-
output_dir

Directory in which generated files are written.

-
-
case

Primary case path used for file detection and classification.

-
-
fill_between_style

Colors and opacity values for ensemble uncertainty bands.

-
-
colorbar_format

Colorbar format specification received from the CLI.

-
-
fc

Figure or axes face color.

-
-
inactive_color

Color assigned to inactive grid cells.

-
-
mask_variable

Variable used to mask spatial-map values.

-
-
suptitle

Figure-level title shared by all subplots.

-
-
colorbar_label

User-provided colorbar label.

-
-
slice_mode

Mode used when retaining wells or faults in an aggregated slice.

-
-
xunits, yunits

Requested spatial unit codes for both coordinate axes.

-
-
xunit, yunit

Formatted spatial unit labels shown on the axes.

-
-
slices

Normalized half-open ranges used for spatial slice aggregation.

-
-
csv_cols

Normalized CSV column indices used for gridded CSV data.

-
-
-
-
-
-
-aggregation: list
-
- -
-
-axis_grid: list
-
- -
-
-caprock_vars: list
-
- -
-
-case: str
-
- -
-
-case_labels: list
-
- -
-
-cases: list
-
- -
-
-cb_formats: list
-
- -
-
-clim: list
-
- -
-
-color_log: list
-
- -
-
-color_log_ticks: list
-
- -
-
-colorbar_format: str
-
- -
-
-colorbar_label: str
-
- -
-
-colorbar_position: tuple[float, float, float, float]
-
- -
-
-colorbar_tick_count: list
-
- -
-
-colorbar_ticks: list
-
- -
-
-colormaps: list
-
- -
-
-colors: list
-
- -
-
-colors_default: list
-
- -
-
-colors_raw: str
-
- -
-
-csv: bool
-
- -
-
-csv_column_summary: bool
-
- -
-
-csv_columns: list
-
- -
-
-difference_input: str
-
- -
-
-disc_colormaps: list
-
- -
-
-discrete: bool
-
- -
-
-distance: list
-
- -
-
-dpi: list
-
- -
-
-dual_grid: list
-
- -
-
-ensemble: int
-
- -
-
-equal_aspect: bool
-
- -
-
-faults: list
-
- -
-
-fc: str
-
- -
-
-figsize: list
-
- -
-
-filename: list
-
- -
-
-fill_between_style: str
-
- -
-
-filters: list
-
- -
-
-fontsize: float
-
- -
-
-gif: bool
-
- -
-
-gif_interval: float
-
- -
-
-gif_loop: bool
-
- -
-
-global_range: bool
-
- -
-
-grid_edges: list
-
- -
-
-hide_map_elements: list
-
- -
-
-histogram: list
-
- -
-
-inactive_color: str
-
- -
-
-layer: bool
-
- -
-
-legend_labels: list
-
- -
-
-legend_location: list
-
- -
-
-linestyle: list
-
- -
-
-linestyle_default: list
-
- -
-
-linewidth: list
-
- -
-
-linewidth_values: list
-
- -
-
-list_variables: bool
-
- -
-
-mask_threshold: float
-
- -
-
-mask_variable: str
-
- -
-
-mass_fracs: list
-
- -
-
-mass_vars: list
-
- -
-
-max_threshold: list
-
- -
-
-min_threshold: list
-
- -
-
-ncolors: int
-
- -
-
-output_dir: str
-
- -
-
-png: bool
-
- -
-
-remove_duplicate_labels: bool
-
- -
-
-restart: list
-
- -
-
-rotation: list
-
- -
-
-rst_range: bool
-
- -
-
-scale_factor: list
-
- -
-
-sensor: bool
-
- -
-
-slice: list
-
- -
-
-slice_mode: str
-
- -
-
-step_plot: bool
-
- -
-
-stress_coefficient: float
-
- -
-
-subplot_grid: list
-
- -
-
-summary: list
-
- -
-
-summary_mass: list
-
- -
-
-suptitle: str
-
- -
-
-time: list
-
- -
-
-time_units: list
-
- -
-
-title: list
-
- -
-
-translation: list
-
- -
-
-units: list
-
- -
-
-variables: list
-
- -
-
-vsum: list
-
- -
-
-vtk: bool
-
- -
-
-vtk_format: list
-
- -
-
-vtk_names: list
-
- -
-
-wells: list
-
- -
-
-xformat: list
-
- -
-
-xlabel: list
-
- -
-
-xlim: list
-
- -
-
-xlog: list
-
- -
-
-xscale: float
-
- -
-
-xtick_count: list
-
- -
-
-xunit: str
-
- -
-
-xunits: str
-
- -
-
-yformat: list
-
- -
-
-ylabel: list
-
- -
-
-ylim: list
-
- -
-
-ylog: list
-
- -
-
-yscale: float
-
- -
-
-ytick_count: list
-
- -
-
-yunit: str
-
- -
-
-yunits: str
-
- -
- -
-
-class plopm.config.config.SimData(init: EclFile = None, unrst: ERst = None, grid: EGrid = None, porv: NDArray = <factory>, dx: NDArray = <factory>, dy: NDArray = <factory>, dz: NDArray = <factory>, active_pv: NDArray = <factory>, active_idx: NDArray = <factory>, steps: list = <factory>, times: list = <factory>, ncells: int = 0, nsteps: int = 0, nx: int = 0, ny: int = 0, nz: int = 0)
-

Bases: object

-

OPM readers, grid properties, and selected report steps for one case.

-

Arrays in global cell order use the full nx * ny * nz grid. Arrays in -active-cell order follow the indexing used by INIT and UNRST properties.

-
-
Attributes:
-
-
init, unrst, grid

OPM readers for static properties, restart properties, and grid geometry.

-
-
porv

Pore volume in global cell order; inactive cells are non-positive.

-
-
dx, dy, dz

Cell dimensions in active-cell order.

-
-
active_pv

Pore volume in active-cell order.

-
-
active_idx

Mapping from global cell indices to active-cell indices.

-
-
steps, times

Selected restart report steps and their simulation times.

-
-
ncells, nsteps

Total grid-cell and available report-step counts.

-
-
nx, ny, nz

Grid dimensions along the i, j, and k axes.

-
-
-
-
-
-
-active_idx: NDArray
-
- -
-
-active_pv: NDArray
-
- -
-
-dx: NDArray
-
- -
-
-dy: NDArray
-
- -
-
-dz: NDArray
-
- -
-
-grid: EGrid
-
- -
-
-init: EclFile
-
- -
-
-ncells: int
-
- -
-
-nsteps: int
-
- -
-
-nx: int
-
- -
-
-ny: int
-
- -
-
-nz: int
-
- -
-
-porv: NDArray
-
- -
-
-steps: list
-
- -
-
-times: list
-
- -
-
-unrst: ERst
-
- -
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.config.html b/docs/plopm.config.html deleted file mode 100644 index 309e328..0000000 --- a/docs/plopm.config.html +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - - plopm.config package — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.config package

-
-

Submodules

-
- -
-
-
-

Module contents

-

Code version

-
-
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.core.html b/docs/plopm.core.html deleted file mode 100644 index edadbdd..0000000 --- a/docs/plopm.core.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - plopm.core package — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.core package

-
-

Submodules

- -
-
-

Module contents

-
-
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.core.plopm.html b/docs/plopm.core.plopm.html deleted file mode 100644 index 14d0ed7..0000000 --- a/docs/plopm.core.plopm.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - plopm.core.plopm module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.core.plopm module

-

Command-line entry point and top-level workflow coordination for plopm.

-

plopm supports three output workflows for OPM Flow simulation results:

-
    -
  • One-dimensional plots and CSV files can be generated from summary vectors, -tabulated functions, grid-cell sensors, layers, histograms, and distances.

  • -
  • Two-dimensional PNG figures and GIF animations can be generated for selected -grid slices, with optional aggregation, masking, differences, wells, and faults.

  • -
  • VTK time series can be generated by combining OPM grid geometry with selected -INIT and UNRST properties.

  • -
-

This module parses and validates command-line arguments, builds the runtime -configuration, selects the appropriate workflow, and reports the generated -files. Data reading, numerical processing, plotting, and file generation are -implemented in the utility modules.

-
-
-plopm.core.plopm.__parse_number_list(option: str, value: str, expected_length: int | None = None) list
-

Parse comma-separated numeric values.

-
-
Parameters:
-
-
optionstr

Option name used in an error message.

-
-
valuestr

Comma-separated values to convert.

-
-
expected_lengthint, optional

Required number of values.

-
-
-
-
Returns:
-
-
list[float]

Parsed numeric values.

-
-
-
-
Raises:
-
-
SystemExit

If a value is not numeric or the length is invalid.

-
-
-
-
-
- -
-
-plopm.core.plopm._check_cmdargs(cmdargs: Namespace) None
-

Validate command-line values and option combinations.

-

The function checks value syntax, accepted choices, mutually exclusive -operations, mode-specific options, and availability of OPM Flow for VTK -generation.

-
-
Parameters:
-
-
cmdargsargparse.Namespace

Parsed arguments returned by _load_parser().

-
-
-
-
Raises:
-
-
SystemExit

If a value is invalid or incompatible options are requested.

-
-
-
-
-
- -
-
-plopm.core.plopm._load_parser(argv: list[str] | None = None) Namespace
-

Create the CLI parser and parse plopm arguments.

-
-
Parameters:
-
-
argvlist[str], optional

Arguments to parse instead of sys.argv[1:].

-
-
-
-
Returns:
-
-
argparse.Namespace

Parsed command-line arguments.

-
-
-
-
-
- -
-
-plopm.core.plopm._parse_number(option: str, value: str) float
-

Parse one numeric command-line value.

-
-
Parameters:
-
-
optionstr

Option name used in an error message.

-
-
valuestr

Value to convert.

-
-
-
-
Returns:
-
-
float

Parsed numeric value.

-
-
-
-
Raises:
-
-
SystemExit

If the value is not numeric.

-
-
-
-
-
- -
-
-plopm.core.plopm.main(argv: list[str] | None = None) None
-

Run the plopm command-line workflow.

-

The function parses and validates CLI arguments, builds the shared -configuration, and dispatches VTK export, one-dimensional plotting, or -two-dimensional map generation. It reports the generated files after the -selected workflow completes.

-
-
Parameters:
-
-
argvlist[str], optional

Arguments to parse instead of sys.argv[1:]. This is primarily used -by tests and programmatic callers.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.html b/docs/plopm.html deleted file mode 100644 index b919d0a..0000000 --- a/docs/plopm.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - plopm package — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm package

-
-

Subpackages

-
- -
-
-
-

Module contents

-

Code version

-
-
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.html b/docs/plopm.utils.html deleted file mode 100644 index cdc811a..0000000 --- a/docs/plopm.utils.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - - - plopm.utils package — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils package

-
-

Submodules

-
- -
-
-
-

Module contents

-
-
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.initialization.html b/docs/plopm.utils.initialization.html deleted file mode 100644 index 1d614f8..0000000 --- a/docs/plopm.utils.initialization.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - plopm.utils.initialization module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.initialization module

-

Build and normalize configuration for plopm workflows.

-

The module converts parsed CLI arguments into PlopmConfig, discovers -simulation cases, normalizes per-variable plotting settings, selects summary or -spatial processing, and defines unit conversions used by the readers.

-
-
-plopm.utils.initialization._find_all_cases(folder: str, suffix: str) list
-

Find all simulation cases below a folder.

-
-
Parameters:
-
-
folderstr

Folder to search recursively.

-
-
suffixstr

File suffix identifying a simulation case.

-
-
-
-
Returns:
-
-
list[str]

Sorted case paths without the identifying suffix.

-
-
-
-
-
- -
-
-plopm.utils.initialization._find_first_case(folder: str, suffix: str) str
-

Find the first simulation case below a folder.

-
-
Parameters:
-
-
folderstr

Folder to search recursively.

-
-
suffixstr

File suffix identifying a simulation case.

-
-
-
-
Returns:
-
-
str

First case path without the suffix, or the input folder when no -matching file is found.

-
-
-
-
-
- -
-
-plopm.utils.initialization._join_block_vars(cfg: PlopmConfig) None
-

Rejoin comma-separated indices in block variables.

-
-
Parameters:
-
-
cfgPlopmConfig

Configuration whose variable expressions are updated in place.

-
-
-
-
-
- -
-
-plopm.utils.initialization.build_config(cmdargs: Namespace) PlopmConfig
-

Build a plopm configuration from parsed CLI arguments.

-

The function expands case and difference-input paths, parses list-like -options, normalizes slice and restart selections, and initializes plotting -defaults shared by summary, map, and VTK workflows.

-
-
Parameters:
-
-
cmdargsargparse.Namespace

Command-line arguments returned by the plopm parser.

-
-
-
-
Returns:
-
-
PlopmConfig

Parsed and partially normalized runtime configuration.

-
-
-
-
-
- -
-
-plopm.utils.initialization.init_maps(cfg: PlopmConfig) None
-

Normalize settings used by spatial maps.

-

The function selects default units, colorbar formats, and colormaps; expands -per-variable limits and formats; and initializes spatial coordinate scales.

-
-
Parameters:
-
-
cfgPlopmConfig

Configuration updated in place for map generation.

-
-
-
-
-
- -
-
-plopm.utils.initialization.init_summary(cfg: PlopmConfig) None
-

Normalize settings used by one-dimensional plots.

-
-
Parameters:
-
-
cfgPlopmConfig

Configuration updated in place with per-variable styles and labels.

-
-
-
-
-
- -
-
-plopm.utils.initialization.is_summary(cfg: PlopmConfig) bool
-

Determine whether the request uses one-dimensional output.

-

The decision considers explicit series options, special tabulated -properties, summary-vector availability, and requests to list variables.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration and primary case path.

-
-
-
-
Returns:
-
-
bool

True when the request should use the summary plotting workflow.

-
-
-
-
-
- -
-
-plopm.utils.initialization.mass_unit(mskl: float) str
-

Get the display unit for a mass scale factor.

-
-
Parameters:
-
-
msklfloat

Factor applied to quantities stored in kilograms.

-
-
-
-
Returns:
-
-
str

Matplotlib-formatted mass unit, or an empty string when unknown.

-
-
-
-
-
- -
-
-plopm.utils.initialization.spatial_unit(unit: str) tuple[float, str]
-

Get the conversion and label for a spatial unit.

-
-
Parameters:
-
-
unitstr

Spatial-unit code.

-
-
-
-
Returns:
-
-
tuple[float, str]

Factor converting metres and the formatted unit label.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.mapping.html b/docs/plopm.utils.mapping.html deleted file mode 100644 index e4e5ca0..0000000 --- a/docs/plopm.utils.mapping.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - plopm.utils.mapping module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.mapping module

-

Prepare slice geometry and map three-dimensional values to two dimensions.

-

The module builds labels and coordinate meshes for xy, xz, and yz slices, -applies optional rotation and translation, and aggregates active-cell values -through the selected grid interval.

-
-
-plopm.utils.mapping.get_xy_slice(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray, str, str, int, int, str, str]
-

Prepare geometry and labels for an xy slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map and slice configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple

Coordinate meshes, display and filename slice labels, mapped grid -dimensions, and coordinate-axis names.

-
-
-
-
-
- -
-
-plopm.utils.mapping.get_xz_slice(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray, str, str, int, int, str, str]
-

Prepare geometry and labels for an xz slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map and slice configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple

Coordinate meshes, display and filename slice labels, mapped grid -dimensions, and coordinate-axis names.

-
-
-
-
-
- -
-
-plopm.utils.mapping.get_yz_slice(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray, str, str, int, int, str, str]
-

Prepare geometry and labels for a yz slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map and slice configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple

Coordinate meshes, display and filename slice labels, mapped grid -dimensions, and coordinate-axis names.

-
-
-
-
-
- -
-
-plopm.utils.mapping.map_xy(cfg: PlopmConfig, data: SimData, var: str, values: NDArray, n: int, mx: int, my: int, features: list | None = None, feature_id: int = 1) NDArray
-

Aggregate active-cell values onto an xy slice.

-

Values are aggregated through the selected k interval. Dual-porosity rows -are included when enabled, and permeability is weighted according to the -vertical flow direction.

-
-
Parameters:
-
-
cfgPlopmConfig

Slice, aggregation, and dual-grid configuration.

-
-
dataSimData

Loaded grid properties and active-cell mapping.

-
-
varstr

Variable name.

-
-
valuesnp.ndarray

Values in active-cell order.

-
-
nint

Map index.

-
-
mx, myint

Mapped grid dimensions.

-
-
featureslist, optional

Wells or faults grouped by label.

-
-
feature_idint, default: 1

Category assigned when mapping one feature.

-
-
-
-
Returns:
-
-
np.ndarray

Values on the flattened xy plotting grid.

-
-
-
-
-
- -
-
-plopm.utils.mapping.map_xz(cfg: PlopmConfig, data: SimData, var: str, values: NDArray, n: int, mx: int, my: int, features: list | None = None, feature_id: int = 1) NDArray
-

Aggregate active-cell values onto an xz slice.

-

Values are aggregated through the selected j interval. Permeability uses -arithmetic or harmonic thickness weighting according to flow direction; -other properties use the configured aggregation or pore-volume weighting.

-
-
Parameters:
-
-
cfgPlopmConfig

Slice and aggregation configuration.

-
-
dataSimData

Loaded grid properties and active-cell mapping.

-
-
varstr

Variable name.

-
-
valuesnp.ndarray

Values in active-cell order.

-
-
nint

Map index.

-
-
mx, myint

Mapped grid dimensions.

-
-
featureslist, optional

Wells or faults grouped by label.

-
-
feature_idint, default: 1

Category assigned when mapping one feature.

-
-
-
-
Returns:
-
-
np.ndarray

Values on the flattened xz plotting grid.

-
-
-
-
-
- -
-
-plopm.utils.mapping.map_yz(cfg: PlopmConfig, data: SimData, var: str, values: NDArray, n: int, mx: int, my: int, features: list | None = None, feature_id: int = 1) NDArray
-

Aggregate active-cell values onto a yz slice.

-

Values are aggregated through the selected i interval. Permeability uses -arithmetic or harmonic thickness weighting according to flow direction; -other properties use the configured aggregation or pore-volume weighting.

-
-
Parameters:
-
-
cfgPlopmConfig

Slice and aggregation configuration.

-
-
dataSimData

Loaded grid properties and active-cell mapping.

-
-
varstr

Variable name.

-
-
valuesnp.ndarray

Values in active-cell order.

-
-
nint

Map index.

-
-
mx, myint

Mapped grid dimensions.

-
-
featureslist, optional

Wells or faults grouped by label.

-
-
feature_idint, default: 1

Category assigned when mapping one feature.

-
-
-
-
Returns:
-
-
np.ndarray

Values on the flattened yz plotting grid.

-
-
-
-
-
- -
-
-plopm.utils.mapping.transform_grid(cfg: PlopmConfig, n: int, xc: NDArray, yc: NDArray) tuple[NDArray, NDArray]
-

Rotate and translate a two-dimensional coordinate mesh.

-
-
Parameters:
-
-
cfgPlopmConfig

Rotation and translation settings.

-
-
nint

Map index.

-
-
xc, ycnp.ndarray

Coordinate meshes to transform.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

Transformed x- and y-coordinate meshes.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.readers.html b/docs/plopm.utils.readers.html deleted file mode 100644 index 30bb6f9..0000000 --- a/docs/plopm.utils.readers.html +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - - - - plopm.utils.readers module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.readers module

-

Read and derive plotting quantities from OPM Flow output.

-

The module opens INIT, UNRST, EGRID, SMSPEC, deck, and CSV data; constructs -plotting coordinates; evaluates variable expressions; and derives saturation, -mass, caprock, distance, well, and fault quantities.

-
-
-plopm.utils.readers._aggregate(var: NDArray, op: str, porv: NDArray) NDArray
-

_aggregate values with the selected method.

-
-
Parameters:
-
-
varnp.ndarray

Values to _aggregate.

-
-
opstr

Aggregation method.

-
-
porvnp.ndarray

Pore-volume weights used by "pvmean".

-
-
-
-
Returns:
-
-
np.ndarray or float

_aggregated values.

-
-
-
-
-
- -
-
-plopm.utils.readers._apply_filter(porvs: NDArray, other: NDArray, op: str, value: float) NDArray
-

Apply a comparison filter to pore-volume values.

-
-
Parameters:
-
-
porvsnp.ndarray

Pore-volume values.

-
-
othernp.ndarray

Values tested by the filter.

-
-
opstr

Comparison operator.

-
-
valuefloat

Comparison threshold.

-
-
-
-
Returns:
-
-
np.ndarray

Pore volume where the condition is true and zero elsewhere.

-
-
-
-
-
- -
-
-plopm.utils.readers._apply_operator(var: NDArray[float64], other: NDArray[float64], op: str) NDArray[float64]
-

Apply an arithmetic or comparison operator.

-
-
Parameters:
-
-
var, othernp.ndarray

Left- and right-hand values.

-
-
opstr

Arithmetic or comparison operator.

-
-
-
-
Returns:
-
-
np.ndarray

Operation result. Failed comparisons are NaN.

-
-
-
-
-
- -
-
-plopm.utils.readers._compute_distance(cfg: PlopmConfig, data: SimData, tokens: list, n: int) tuple[NDArray, NDArray]
-

Compute distance from selected cells to target points.

-
-
Parameters:
-
-
cfgPlopmConfig

Distance and sensor configuration.

-
-
dataSimData

Loaded simulation data.

-
-
tokenslist

Parsed expression selecting active cells.

-
-
nint

Plot index.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

Finite distances and their simulation times.

-
-
-
-
-
- -
-
-plopm.utils.readers._find_keyword(case: str, vec: str) str
-

Find the deck file containing an OPM keyword.

-
-
Parameters:
-
-
casestr

Simulation-case stem.

-
-
vecstr

OPM keyword to locate.

-
-
-
-
Returns:
-
-
str

DATA or included file containing the keyword.

-
-
-
-
-
- -
-
-plopm.utils.readers._get_caprock(data: SimData, name: str, step: int, stress: float) tuple[NDArray, str]
-

Compute a caprock-integrity quantity.

-
-
Parameters:
-
-
dataSimData

Loaded static and restart properties.

-
-
namestr

Requested caprock variable.

-
-
stepint

Restart report step.

-
-
stressfloat

Vertical stress coefficient.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, str]

Computed values and unit label.

-
-
-
-
-
- -
-
-plopm.utils.readers._get_mass(data: SimData, name: str, step: int) NDArray
-

Compute component masses and mass fractions.

-
-
Parameters:
-
-
dataSimData

Loaded restart data and pore volume.

-
-
namestr

Requested derived variable.

-
-
stepint

Restart report step.

-
-
-
-
Returns:
-
-
np.ndarray

Requested component quantity.

-
-
-
-
-
- -
-
-plopm.utils.readers._get_saturation(unrst: ERst, name: str, step: int) NDArray
-

Derive a missing phase saturation.

-
-
Parameters:
-
-
unrstOpmRestart

UNRST reader.

-
-
name{“soil”, “swat”, “sgas”}

Saturation to derive.

-
-
stepint

Restart report step.

-
-
-
-
Returns:
-
-
np.ndarray

Requested phase saturation.

-
-
-
-
-
- -
-
-plopm.utils.readers._grid_indices(name: str, nx: int, ny: int, nz: int) list
-

Create one-based grid indices in global cell order.

-
-
Parameters:
-
-
name{“index_i”, “index_j”, “index_k”}

Grid axis to index.

-
-
nx, ny, nzint

Grid dimensions.

-
-
-
-
Returns:
-
-
list[int]

One-based indices for all grid cells.

-
-
-
-
-
- -
-
-plopm.utils.readers._read_histogram(cfg: PlopmConfig, data: SimData, tokens: list, step: int) NDArray
-

Read values used to create a histogram.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration.

-
-
dataSimData

Loaded simulation data.

-
-
tokenslist

Parsed variable-expression tokens.

-
-
stepint

Restart report step.

-
-
-
-
Returns:
-
-
np.ndarray

Values in global cell order with inactive cells set to NaN.

-
-
-
-
-
- -
-
-plopm.utils.readers._read_values(cfg: PlopmConfig, data: SimData, tokens: list, n: int, ntot: list) tuple[NDArray, NDArray]
-

Read an _aggregated time series or grid-axis profile.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized series configuration.

-
-
dataSimData

Loaded simulation data.

-
-
tokenslist

Parsed variable-expression tokens.

-
-
nint

Plot index.

-
-
ntotlist

Restart report steps to evaluate.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

Values and corresponding time or grid coordinates.

-
-
-
-
-
- -
-
-plopm.utils.readers._resolve_var(cfg: PlopmConfig, data: SimData, key_up: str, key_low: str, step: int, init: EclFile, unrst: ERst, mass_all: list, caprock_list: list)
-

Resolve a variable from stored or derived quantities.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration.

-
-
dataSimData

Loaded simulation data.

-
-
key_up, key_lowstr

OPM keyword and normalized variable name.

-
-
stepint

Restart report step.

-
-
initOpmFile

INIT reader.

-
-
unrstOpmRestart

UNRST reader.

-
-
mass_all, caprock_listlist

Supported derived variable names.

-
-
-
-
Returns:
-
-
np.ndarray or None

Resolved values, or None when unavailable.

-
-
-
-
-
- -
-
-plopm.utils.readers._select_mass(name: str, co2_g: NDArray, co2_d: NDArray, h2o_l: NDArray, h2o_v: NDArray, x_l_co2: NDArray, x_g_h2o: NDArray) NDArray
-

Select a mass or mass-fraction result by name.

-
-
Parameters:
-
-
namestr

Requested derived variable.

-
-
co2_g, co2_dnp.ndarray

Free and dissolved CO2 masses.

-
-
h2o_l, h2o_vnp.ndarray

Liquid and vapor water masses.

-
-
x_l_co2, x_g_h2onp.ndarray

CO2-in-liquid and water-in-gas mass fractions.

-
-
-
-
Returns:
-
-
np.ndarray

Selected mass or mass fraction.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_faults(cfg: PlopmConfig, n: int) tuple[list, list]
-

Read faults intersecting the selected slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Case and slice configuration.

-
-
nint

Case index.

-
-
-
-
Returns:
-
-
tuple[list, list[str]]

Grid segments grouped by fault and the fault names.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_unit(name: str) str
-

Get the display unit for a variable.

-
-
Parameters:
-
-
namestr

Variable name.

-
-
-
-
Returns:
-
-
str

Matplotlib-formatted unit label.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_wells(cfg: PlopmConfig, n: int) tuple[list, list]
-

Read wells intersecting the selected slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Case and slice configuration.

-
-
nint

Case index.

-
-
-
-
Returns:
-
-
tuple[list, list[str]]

Completion intervals grouped by well and the well names.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_xy_coords(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray]
-

Build coordinate meshes for an xy slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

X- and y-coordinate meshes.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_xz_coords(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray]
-

Build coordinate meshes for an xz slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

X- and z-coordinate meshes.

-
-
-
-
-
- -
-
-plopm.utils.readers.get_yz_coords(cfg: PlopmConfig, data: SimData, n: int) tuple[NDArray, NDArray]
-

Build coordinate meshes for a yz slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
dataSimData

Loaded grid data.

-
-
nint

Slice index.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray]

Y- and z-coordinate meshes.

-
-
-
-
-
- -
-
-plopm.utils.readers.read_case(deck: str, gif: bool, vtk: bool, variables: list, restart: list, filters: list, n: int = 0) SimData
-

Open the OPM output required for one simulation case.

-
-
Parameters:
-
-
deckstr

Simulation-case stem without an extension.

-
-
gif, vtkbool

Output modes controlling restart and grid loading.

-
-
variableslist

Requested variables or expressions.

-
-
restartlist

Requested restart report steps.

-
-
filterslist

Property-filter expressions.

-
-
nint, default: 0

Case index used to select per-case settings.

-
-
-
-
Returns:
-
-
SimData

Loaded readers, grid properties, and report-step metadata.

-
-
-
-
-
- -
-
-plopm.utils.readers.read_csv_grid(cfg: PlopmConfig, deck: str, n: int) tuple[NDArray, NDArray, int, int, str, str]
-

Read coordinate meshes from a regular CSV grid.

-
-
Parameters:
-
-
cfgPlopmConfig

CSV column and animation configuration.

-
-
deckstr

CSV path without the extension.

-
-
nint

Map index.

-
-
-
-
Returns:
-
-
tuple

Coordinate meshes, dimensions, and axis names.

-
-
-
-
-
- -
-
-plopm.utils.readers.read_quantity(deck: str, data: SimData, name: str, step: int, scale: float, mass: list[str], mass_all: list[str], caprock: list[str], stress: float, filters: str, isgif: bool, vmin: str, vmax: str, cvs: list) tuple[str, NDArray]
-

Read and transform one spatial or VTK quantity.

-
-
Parameters:
-
-
deckstr

Simulation-case stem or CSV path.

-
-
dataSimData

Loaded simulation data.

-
-
namestr

Variable name or expression.

-
-
stepint

Restart report step.

-
-
scalefloat

Scale factor applied to derived values.

-
-
mass, mass_all, caprocklist[str]

Supported derived-variable groups.

-
-
stressfloat

Stress coefficient for caprock quantities.

-
-
filtersstr

Property-filter expression.

-
-
isgifbool

Whether the CSV path contains a restart placeholder.

-
-
vmin, vmaxstr

Optional value thresholds.

-
-
cvslist

CSV input and column settings.

-
-
-
-
Returns:
-
-
tuple[str, np.ndarray]

Unit label and quantity values.

-
-
-
-
-
- -
-
-plopm.utils.readers.read_series(cfg: PlopmConfig, case: str, values: str, tunit: str, qskl: float, n: int) tuple[NDArray, NDArray, str, str]
-

Read one one-dimensional series for plotting.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized series configuration.

-
-
casestr

Simulation-case stem or CSV path.

-
-
valuesstr

Variable name or expression.

-
-
tunitstr

Requested time-unit code.

-
-
qsklfloat

Scale factor applied to values.

-
-
nint

Plot or case index.

-
-
-
-
Returns:
-
-
tuple[np.ndarray, np.ndarray, str, str]

Coordinates, values, coordinate unit, and value unit.

-
-
-
-
-
- -
-
-plopm.utils.readers.time_unit(times: str) tuple[float, str]
-

Get the conversion and label for a time unit.

-
-
Parameters:
-
-
timesstr

Time-unit code or "dates".

-
-
-
-
Returns:
-
-
tuple[float, str]

Factor converting OPM days and the axis label.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.terminal.html b/docs/plopm.utils.terminal.html deleted file mode 100644 index a27d8a8..0000000 --- a/docs/plopm.utils.terminal.html +++ /dev/null @@ -1,388 +0,0 @@ - - - - - - - - - plopm.utils.terminal module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.terminal module

-

Format plopm help text and command-line messages.

-

The module hides deprecated aliases from --help, reports their replacements, -and applies ANSI colors only when supported by the selected output stream.

-
-
-class plopm.utils.terminal.PlopmHelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, color=True)
-

Bases: ArgumentDefaultsHelpFormatter

-

Argparse formatter that hides deprecated option aliases.

-

Current options retain the standard -argparse.ArgumentDefaultsHelpFormatter layout and default values.

-
-
-_format_action_invocation(action: Action) str
-

Format one argparse action using current option names.

-
-
Parameters:
-
-
actionargparse.Action

Action whose option invocation is displayed in CLI help.

-
-
-
-
Returns:
-
-
str

Formatted invocation with deprecated aliases omitted.

-
-
-
-
-
- -
- -
-
-plopm.utils.terminal._colorize(text: str, code: str, stream: object = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>) str
-

Wrap text in an ANSI color sequence when supported.

-
-
Parameters:
-
-
textstr

Text to format.

-
-
codestr

ANSI Select Graphic Rendition code.

-
-
streamobject, default: sys.stderr

Output stream used to determine color support.

-
-
-
-
Returns:
-
-
str

Colored text, or the original text when colors are unavailable.

-
-
-
-
-
- -
-
-plopm.utils.terminal._supports_color(stream: object = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>) bool
-

Check whether an output stream supports ANSI colors.

-
-
Parameters:
-
-
streamobject, default: sys.stderr

Output stream to inspect.

-
-
-
-
Returns:
-
-
bool

True for an interactive stream unless colors are disabled by -NO_COLOR or TERM=dumb.

-
-
-
-
-
- -
-
-plopm.utils.terminal.cli_current_value(value: str) str
-

Format a current CLI option or value.

-
-
Parameters:
-
-
valuestr

Option or value to display.

-
-
-
-
Returns:
-
-
str

Quoted value with current-option styling when supported.

-
-
-
-
-
- -
-
-plopm.utils.terminal.cli_deprecated_value(value: str) str
-

Format a deprecated CLI option or value.

-
-
Parameters:
-
-
valuestr

Option or value to display.

-
-
-
-
Returns:
-
-
str

Quoted value with deprecated-option styling when supported.

-
-
-
-
-
- -
-
-plopm.utils.terminal.cli_error_value(value: str) str
-

Format an invalid CLI option or value.

-
-
Parameters:
-
-
valuestr

Option or value to display.

-
-
-
-
Returns:
-
-
str

Quoted value with error styling when supported.

-
-
-
-
-
- -
-
-plopm.utils.terminal.cli_info_value(value: str) str
-

Format an informational CLI option or value.

-
-
Parameters:
-
-
valuestr

Option or value to display.

-
-
-
-
Returns:
-
-
str

Quoted value with informational styling when supported.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_error(message: str) NoReturn
-

Raise a fatal command-line error.

-
-
Parameters:
-
-
messagestr

Error message displayed after the plopm label.

-
-
-
-
Raises:
-
-
SystemExit

Always raised with the formatted error message.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_info(message: str) None
-

Display an informational command-line message.

-
-
Parameters:
-
-
messagestr

Message displayed on standard output.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_name(stream: object = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>) str
-

Format the plopm program name.

-
-
Parameters:
-
-
streamobject, default: sys.stderr

Output stream used to determine color support.

-
-
-
-
Returns:
-
-
str

Program name with gradient colors when supported.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_success(output_dir: str, filenames: list[str]) None
-

Display the generated output location and filenames.

-
-
Parameters:
-
-
output_dirstr

Directory containing the generated files.

-
-
filenameslist[str]

Generated filenames.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_tip(message: str) None
-

Display a command-line suggestion.

-
-
Parameters:
-
-
messagestr

Suggestion displayed on standard output.

-
-
-
-
-
- -
-
-plopm.utils.terminal.plopm_warning(message: str) None
-

Display a non-fatal command-line warning.

-
-
Parameters:
-
-
messagestr

Warning message displayed on standard error.

-
-
-
-
-
- -
-
-plopm.utils.terminal.warn_deprecated_options(argv: Sequence[str]) None
-

Warn once for each deprecated option in an argument list.

-
-
Parameters:
-
-
argvSequence[str]

Command-line arguments, excluding or including the executable name.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.write_oned.html b/docs/plopm.utils.write_oned.html deleted file mode 100644 index b8cc71f..0000000 --- a/docs/plopm.utils.write_oned.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - - - - plopm.utils.write_oned module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.write_oned module

-

Create one-dimensional plots and tabular output from OPM results.

-

The module reads summary vectors, grid-derived series, and optional CSV data. -It also supports ensemble statistics, subplot layouts, and PNG or CSV output.

-
-
-plopm.utils.write_oned._clean_name(name: str) str
-

Convert a variable expression to a filename-safe stem.

-
-
Parameters:
-
-
namestr

Variable expression or proposed filename stem.

-
-
-
-
Returns:
-
-
str

Name with operators and separators replaced.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._get_deck_name(name: str) str
-

Get a display name from a case or include-file path.

-
-
Parameters:
-
-
namestr

Case path or include filename.

-
-
-
-
Returns:
-
-
str

Lowercase basename without an .inc extension.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._get_label(cfg: PlopmConfig, name: str, var_index: int, name_index: int) str
-

Select the legend label for a plotted series.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration containing ensemble cases and plot styles.

-
-
namestr

Simulation-case path.

-
-
var_indexint

Index of the plotted variable.

-
-
name_indexint

Index of the case within the variable group.

-
-
-
-
Returns:
-
-
str

User-defined label or a label derived from the case path.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._plot_ensemble(cfg: PlopmConfig, axes: Axes | ndarray) tuple[str, str, float, float, float, float]
-

Plot ensemble statistics for the first requested variable.

-

Each realization is interpolated to a shared coordinate array. Depending on -cfg.ensemble, the function plots the mean, a one-standard-deviation band, -the bounding realizations, or both.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration containing ensemble cases and plot styles.

-
-
axesmatplotlib.axes.Axes or np.ndarray

Axis, or array of axes, on which to draw the ensemble.

-
-
-
-
Returns:
-
-
tuple[str, str, float, float, float, float]

Time unit, value unit, and (min_t, max_t, min_v, max_v) limits.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._save_summary_csv(cfg: PlopmConfig, deckn: str, var: NDArray, quan: str, index: int) str
-

Write non-NaN summary values to a CSV file.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration containing ensemble cases and plot styles.

-
-
decknstr

Case name used in the default filename.

-
-
varnp.ndarray

Values to write.

-
-
quanstr

Variable expression used in the default filename.

-
-
indexint

Plot index used to select a custom filename.

-
-
-
-
Returns:
-
-
str

Name of the generated CSV file.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._save_summary_png(cfg: PlopmConfig, deckn: str, quan: str, index: int, fig: Figure) str
-

Save a summary figure as a PNG file.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized configuration containing ensemble cases and plot styles.

-
-
decknstr

Case name used in the default filename.

-
-
quanstr

Variable expression used in the default filename.

-
-
indexint

Plot index used to select filename and resolution settings.

-
-
figmatplotlib.figure.Figure

Figure to save.

-
-
-
-
Returns:
-
-
str

Name of the generated PNG file.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._set_formatted_ticks(axis: Axes, labels: NDArray, value_format: str, axis_name: str) None
-

Set explicitly formatted ticks on one axis.

-
-
Parameters:
-
-
axismatplotlib.axes.Axes

Axis to update.

-
-
labelsnp.ndarray

Numeric tick locations.

-
-
value_formatstr

Python format specification for each label.

-
-
axis_name{“x”, “y”}

Coordinate axis to update.

-
-
-
-
-
- -
-
-plopm.utils.write_oned._update_limits(time: NDArray, var: NDArray, tunit: str, min_t: float, max_t: float, min_v: float, max_v: float, xlow: float, ylow: float, first: bool) tuple[float, float, float, float]
-

Update the data limits from one plotted series.

-
-
Parameters:
-
-
time, varnp.ndarray

Time coordinates and variable values.

-
-
tunitstr

Time-axis label. "Dates" selects date handling.

-
-
min_t, max_tfloat

Current time limits.

-
-
min_v, max_vfloat

Current variable limits.

-
-
xlow, ylowfloat

Lower bounds used to exclude invalid logarithmic values.

-
-
firstbool

Whether this is the first series included in the limits.

-
-
-
-
Returns:
-
-
tuple[float, float, float, float]

Updated (min_t, max_t, min_v, max_v) limits.

-
-
-
-
-
- -
-
-plopm.utils.write_oned.make_plots(cfg: PlopmConfig) list[str]
-

Create the requested one-dimensional plots and CSV files.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized plotting configuration.

-
-
-
-
Returns:
-
-
list[str]

Names of the generated files.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.write_twod.html b/docs/plopm.utils.write_twod.html deleted file mode 100644 index 2352cab..0000000 --- a/docs/plopm.utils.write_twod.html +++ /dev/null @@ -1,715 +0,0 @@ - - - - - - - - - plopm.utils.write_twod module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.write_twod module

-

Create two-dimensional maps and animations from OPM results.

-

The module prepares grid geometry, maps three-dimensional properties onto -selected slices, and writes PNG or GIF output with optional masks, differences, -well and fault overlays, and shared color limits.

-
-
-plopm.utils.write_twod._add_label(features: list, label_index: int, label_name: str, colour: NDArray) None
-

Draw one feature label when the feature is present.

-
-
Parameters:
-
-
featureslist

Feature locations grouped by label.

-
-
label_indexint

Index of the feature group.

-
-
label_namestr

Text shown beside the categorical colorbar.

-
-
colournp.ndarray

Colors assigned to feature groups.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._add_map_overlay(fig: Figure, cfg: PlopmConfig, imag: _ScalarMappable, divider: AxesDivider, vect: NDArray, n: int, var: str, features: list | None, labels: list[str]) None
-

Add a categorical colorbar and labels for map features.

-
-
Parameters:
-
-
figmatplotlib.figure.Figure

Figure containing the map.

-
-
cfgPlopmConfig

Initialized map configuration.

-
-
imagmatplotlib.cm.ScalarMappable

Mappable used to construct the colorbar.

-
-
dividermpl_toolkits.axes_grid1.axes_divider.AxesDivider

Divider associated with the map axis.

-
-
vectnp.ndarray

Categorical colorbar tick values.

-
-
nint

Variable index.

-
-
varstr

Categorical variable, such as "wells" or "faults".

-
-
featureslist, optional

Feature locations grouped by label.

-
-
labelslist[str]

Feature names.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._apply_diff_and_log(cfg: PlopmConfig, diffa: list[NDArray], quaa: NDArray, var_index: int, restart_index: int) None
-

Apply difference and logarithmic transformations in place.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
diffalist[np.ndarray]

Mapped difference values.

-
-
quaanp.ndarray

Mapped values to transform.

-
-
var_indexint

Variable index.

-
-
restart_indexint

Restart-step index used to select a cached difference map.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._case_name(deck: str) str
-

Get a lowercase case name from a path.

-
-
Parameters:
-
-
deckstr

Simulation-case path.

-
-
-
-
Returns:
-
-
str

Final path component in lowercase.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._clean_name(name: str) str
-

Convert a variable expression to a filename-safe stem.

-
-
Parameters:
-
-
namestr

Variable expression or filename stem.

-
-
-
-
Returns:
-
-
str

Name with operators and spaces replaced.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._create_figure(rows: int = 1, columns: int = 1, layout: str | None = None) tuple[Figure, Axes]
-

Create a Matplotlib figure and axes.

-
-
Parameters:
-
-
rows, columnsint, default: 1

Number of subplot rows and columns.

-
-
layoutstr, optional

Matplotlib layout engine.

-
-
-
-
Returns:
-
-
tuple

Created figure and axes.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._delete_extra_axes(axes: NDArray[Any], keep: int, fig: Figure) None
-

Remove unused subplot axes.

-
-
Parameters:
-
-
axesnp.ndarray

Subplot axes.

-
-
keepint

Number of axes to retain.

-
-
figmatplotlib.figure.Figure

Figure containing the axes.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._draw_frame(t: int, deck: str, fig: Figure, axes: Any, original_loc: list[Any], cb: list[str], cmin: list[float], cmax: list[float], maska: list[Any], diffa: list[NDArray], named: str, deckd: str, slice_title: str, slice_name: str, cfg: PlopmConfig, generated_files: list[str], n: int, data: SimData, xc: NDArray, yc: NDArray, skip: int, sub1: int, mx: int, my: int, xname: str, yname: str) Iterable[Artist]
-

Draw all maps belonging to one animation frame.

-

This dispatcher selects cases, variables, restart steps, and subplot -positions before delegating each map to draw_map().

-
-
Parameters:
-
-
tint

Animation-frame or restart-step index.

-
-
deckstr

Primary simulation-case stem.

-
-
figmatplotlib.figure.Figure

Figure receiving the maps.

-
-
axesmatplotlib.axes.Axes or np.ndarray

Target axes.

-
-
original_loc, cblist

Original axes locators and active colorbars.

-
-
cmin, cmaxlist[float]

Color limits for each variable or map.

-
-
maska, diffalist

Mapped masks and cached difference arrays.

-
-
named, deckdstr

Display names for the primary and difference cases.

-
-
slice_title, slice_namestr

Human-readable slice descriptions.

-
-
cfgPlopmConfig

Initialized map configuration.

-
-
generated_fileslist[str]

Generated filenames updated during rendering.

-
-
nint

Current variable or case index.

-
-
dataSimData

Loaded simulation data.

-
-
xc, ycnp.ndarray

Coordinate meshes.

-
-
skip, sub1int

Subplot-control values.

-
-
mx, myint

Mapped grid dimensions.

-
-
xname, ynamestr

Coordinate-axis names.

-
-
-
-
Returns:
-
-
list[matplotlib.artist.Artist]

Empty artist list required by the animation callback.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._draw_map(deck: str, fig: Figure, axes: Any, original_loc: list[Any], cb: list[Any], cmin: list[float], cmax: list[float], maska: list[Any], diffa: list[NDArray], named: str, deckd: str, slice_title: str, slice_name: str, cfg: PlopmConfig, generated_files: list[str], data: SimData, t: int, n: int, k: int, xc: NDArray, yc: NDArray, sub1: int, mx: int, my: int, xname: str, yname: str) None
-

Draw and optionally save one spatial map.

-
-
Parameters:
-
-
deckstr

Simulation-case stem.

-
-
figmatplotlib.figure.Figure

Figure receiving the map.

-
-
axesmatplotlib.axes.Axes or np.ndarray

Target axes.

-
-
original_loc, cblist

Original axes locators and active colorbars.

-
-
cmin, cmaxlist[float]

Configured color limits.

-
-
maska, diffalist

Mapped masks and cached difference arrays.

-
-
named, deckdstr

Display names for the primary and difference cases.

-
-
slice_title, slice_namestr

Human-readable slice descriptions.

-
-
cfgPlopmConfig

Initialized map configuration.

-
-
generated_fileslist[str]

Generated filenames updated when a PNG is saved.

-
-
dataSimData

Loaded simulation data.

-
-
t, n, kint

Restart-step, variable, and subplot indices.

-
-
xc, ycnp.ndarray

Coordinate meshes.

-
-
sub1int

Number of subplot columns.

-
-
mx, myint

Mapped grid dimensions.

-
-
xname, ynamestr

Coordinate-axis names.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._formatted_ticks(values: NDArray, scale: float, value_format: str) tuple[list[float], list[str]]
-

Format scaled tick locations and labels.

-
-
Parameters:
-
-
valuesnp.ndarray

Unscaled tick values.

-
-
scalefloat

Coordinate scale factor.

-
-
value_formatstr

Python format specification.

-
-
-
-
Returns:
-
-
tuple[list[float], list[str]]

Scaled tick locations and formatted labels.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._get_clim(cfg: PlopmConfig) tuple[SimData, NDArray, NDArray, list[float], list[float], list[NDArray]]
-

Determine color limits and cached difference maps.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
-
-
Returns:
-
-
tuple

Last loaded simulation data, coordinate meshes, color minima and -maxima, and cached difference arrays.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._get_masks(cfg: PlopmConfig) list[NDArray]
-

Read and map masks for all configured cases.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
-
-
Returns:
-
-
list[np.ndarray]

Mapped mask arrays.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._map_values(cfg: PlopmConfig, data: SimData, var: str, values: NDArray, slide_index: int, map_index: int, mx: int, my: int, use_csv: bool = False) NDArray
-

Map quantity values onto the selected two-dimensional slice.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
dataSimData

Loaded simulation data.

-
-
varstr

Variable name.

-
-
valuesnp.ndarray

Values in active-cell or CSV order.

-
-
slide_index, map_indexint

Indices selecting the slice and its mapping settings.

-
-
mx, myint

Mapped grid dimensions.

-
-
use_csvbool, default: False

Whether values already use the two-dimensional CSV layout.

-
-
-
-
Returns:
-
-
np.ndarray

Values arranged on the selected map.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._normalize_axis(axes: Axes | NDArray[Any]) NDArray
-

Return axes as a one-dimensional-compatible array.

-
-
Parameters:
-
-
axesmatplotlib.axes.Axes or np.ndarray

Axes returned by Matplotlib.

-
-
-
-
Returns:
-
-
np.ndarray

Array containing the supplied axes.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._prepare_colorbars(axes: NDArray[Any]) tuple[list[Any], list[str]]
-

Initialize colorbar state for each subplot.

-
-
Parameters:
-
-
axesnp.ndarray

Subplot axes.

-
-
-
-
Returns:
-
-
tuple[list, list]

Original axes locators and empty colorbar slots.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._prepare_map(cfg: PlopmConfig, deck: str, n: int) tuple[SimData, NDArray, NDArray, str, str, str, int, int, str, str]
-

Prepare simulation data and coordinates for one map.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
deckstr

Simulation-case stem or CSV input path.

-
-
nint

Case or map index used to select configuration values.

-
-
-
-
Returns:
-
-
tuple

Simulation data, coordinate meshes, case and slice labels, mesh -dimensions, and coordinate-axis names.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._remove_colorbar(axes: Any, original_loc: list[Any], cb: list[Any], colorbar_index: int) tuple[Any, list[Any]]
-

Remove a colorbar and restore its axes locator.

-
-
Parameters:
-
-
axesmatplotlib.axes.Axes or np.ndarray

Map axes.

-
-
original_loclist

Original axes locators.

-
-
cblist

Active colorbar objects.

-
-
colorbar_indexint

Colorbar and axes index to restore.

-
-
-
-
Returns:
-
-
tuple

Updated axes and colorbar list.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._save_animation(cfg: PlopmConfig, im_ani: FuncAnimation, name: str) str
-

Save a Matplotlib animation as a GIF.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
im_animatplotlib.animation.FuncAnimation

Animation to save.

-
-
namestr

Output filename without extension.

-
-
-
-
Returns:
-
-
str

Name of the generated GIF file.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._save_map(fig: Figure, cfg: PlopmConfig, data: SimData, generated_files: list[str], named: str, var: str, slice_name: str, t: int, save_index: int) None
-

Save the current spatial map as a PNG file.

-
-
Parameters:
-
-
figmatplotlib.figure.Figure

Figure containing the map.

-
-
cfgPlopmConfig

Output filename, directory, resolution, and face-color settings.

-
-
dataSimData

Simulation data containing the selected restart steps.

-
-
generated_fileslist[str]

Generated filenames updated in place.

-
-
namedstr

Case name used in the default filename.

-
-
varstr

Plotted variable name or expression.

-
-
slice_namestr

Slice description used in the default filename.

-
-
tint

Index of the restart step being plotted.

-
-
save_indexint

Index used to select a custom filename.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._set_axis(fig: Figure, axes: Any, cfg: PlopmConfig, data: SimData, name: str, n: int, t: int, k: int, n_s: int, unit: str, xc: NDArray, yc: NDArray, extinf: float, named: str, deckd: str, defcol: bool, slice_title: str, feature_id: int) None
-

Configure labels, limits, ticks, and annotations for a map axis.

-
-
Parameters:
-
-
figmatplotlib.figure.Figure

Figure containing the map.

-
-
axesmatplotlib.axes.Axes or np.ndarray

Map axes.

-
-
cfgPlopmConfig

Initialized map configuration.

-
-
dataSimData

Loaded simulation data.

-
-
namestr

Variable name.

-
-
n, t, k, n_sint

Variable, restart, subplot, and slice indices.

-
-
unitstr

Variable unit label.

-
-
xc, ycnp.ndarray

Coordinate meshes.

-
-
extinffloat

Padding added to map extents.

-
-
named, deckdstr

Display names for the primary and difference cases.

-
-
defcolbool

Whether default categorical colors are used.

-
-
slice_titlestr

Human-readable slice description.

-
-
feature_idint

Number assigned to the active well or fault feature.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._set_axis_ticks(axis: Any, axis_name: str, labels: NDArray, scale: float, value_format: str, remove_axis: int) None
-

Set formatted ticks on one coordinate axis.

-
-
Parameters:
-
-
axismatplotlib.axes.Axes or np.ndarray

Map axes.

-
-
axis_name{“x”, “y”}

Coordinate axis to update.

-
-
labelsnp.ndarray

Tick values before scaling.

-
-
scalefloat

Coordinate scale factor.

-
-
value_formatstr

Python format specification.

-
-
remove_axisint

Nonzero when the selected axis is hidden.

-
-
-
-
-
- -
-
-plopm.utils.write_twod._update_color_range(quaa: NDArray, cmin: list[float], cmax: list[float]) None
-

Update the current finite color range.

-
-
Parameters:
-
-
quaanp.ndarray

Mapped values included in the color range.

-
-
cminlist[float]

Color minima.

-
-
cmaxlist[float]

Color minima.

-
-
-
-
-
- -
-
-plopm.utils.write_twod.make_maps(cfg: PlopmConfig) list[str]
-

Create the requested spatial maps and animations.

-
-
Parameters:
-
-
cfgPlopmConfig

Initialized map configuration.

-
-
-
-
Returns:
-
-
list[str]

Names of the generated PNG and GIF files.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/plopm.utils.write_vtk.html b/docs/plopm.utils.write_vtk.html deleted file mode 100644 index 067d600..0000000 --- a/docs/plopm.utils.write_vtk.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - - - - - plopm.utils.write_vtk module — plopm documentation - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
- -
-
-
-
- -
-

plopm.utils.write_vtk module

-

Create VTK files from OPM Flow simulation results.

-

The module runs a minimal OPM Flow job when grid geometry is unavailable, -populates VTU cell-data arrays for selected restart steps, and writes the PVD -collection used to open the resulting time series.

-
-
-plopm.utils.write_vtk._check_integer_conversion(values: NDArray, var: str, vtkformat: str, target_dtype: type, warning_keys: set[tuple[str, str, str]]) None
-

Warn about unsafe conversion to an integer VTK type.

-

Warnings cover non-numeric or non-finite values, negative values converted -to unsigned integers, decimal truncation, and values outside the target -integer range.

-
-
Parameters:
-
-
valuesnp.ndarray

Quantity values to inspect.

-
-
varstr

Variable name used in warning messages.

-
-
vtkformatstr

Requested VTK data type.

-
-
target_dtypetype

NumPy dtype used for conversion.

-
-
warning_keysset[tuple[str, str, str]]

Keys for warnings already emitted.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk._format_vtk_array(values: NDArray, target_dtype: type) str
-

Format values for an ASCII VTK DataArray.

-
-
Parameters:
-
-
valuesnp.ndarray

Values to flatten and convert.

-
-
target_dtypetype

NumPy dtype used for the output values.

-
-
-
-
Returns:
-
-
str

Tab-indented values ready for insertion into a VTU file.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk._vtk_flags() tuple[str, str]
-

Build OPM Flow options for a minimal VTK run.

-
-
Returns:
-
-
tuple[str, str]

General VTK options and optional thermal-model options.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk._warn_once(warning_keys: set, warning_key, message: str) None
-

Emit a warning once for a unique key.

-
-
Parameters:
-
-
warning_keysset

Keys for warnings already emitted.

-
-
warning_key

Hashable key identifying the warning condition.

-
-
messagestr

Warning message.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk._write_pvd(save: list, dname: str, restart: list, tnrst: list, output: str, k: int) None
-

Write a PVD collection for a VTU time series.

-
-
Parameters:
-
-
savelist

Optional output stems for each case.

-
-
dnamestr

Default case name.

-
-
restartlist

Restart report steps included in the collection.

-
-
tnrstlist

Simulation times indexed by restart report step.

-
-
outputstr

Output directory.

-
-
kint

Case index used to select the output stem.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk._write_vtk_data(case: str, data: SimData, output: str, dname: str, save: list, variables: list, vtkformat_list: list, vtknames: list, k: int, scales: list[str], mass: list[str], mass_all: list[str], caprock: list[str], stress: float, filterss: str) None
-

Populate grid VTU files with simulation cell data.

-
-
Parameters:
-
-
casestr

Simulation-case stem.

-
-
dataSimData

Loaded OPM simulation data.

-
-
outputstr

Output directory.

-
-
dnamestr

Default case name.

-
-
savelist

Optional output stems for each case.

-
-
variableslist

Variables or expressions written as cell data.

-
-
vtkformat_listlist

VTK data type selected for each variable.

-
-
vtknameslist

Optional VTK array names.

-
-
kint

Case index used to select output settings.

-
-
scaleslist[str]

Scale factor applied to each variable.

-
-
mass, mass_alllist[str]

Mass variables and all supported mass-related variables.

-
-
caprocklist[str]

Supported caprock-integrity variables.

-
-
stressfloat

Vertical stress coefficient used for caprock quantities.

-
-
filterssstr

Filter expression applied while reading quantities.

-
-
-
-
-
- -
-
-plopm.utils.write_vtk.make_vtks(flow: str, names: list, output: str, save: list, restart: list, variables: list, vtkformat_list: list, vtknames: list, gif: bool, vtk: bool, filters: list, scales: list[str], mass: list[str], mass_all: list[str], caprock: list[str], stress: float, filterss: list[str]) list
-

Create VTK time-series output for the configured cases.

-

A minimal OPM Flow run creates the grid-only VTU file when needed. Selected -properties are then read from INIT or UNRST output and written to one VTU -file per restart step.

-
-
Parameters:
-
-
flowstr

Command used to run OPM Flow.

-
-
nameslist

Simulation-case stems grouped by the CLI input.

-
-
outputstr

Directory in which VTK files are written.

-
-
savelist

Optional output stems for each case.

-
-
restartlist

Restart report steps to export.

-
-
variableslist

Variables or expressions written as cell data.

-
-
vtkformat_listlist

VTK data type selected for each variable.

-
-
vtknameslist

Optional VTK array names for each variable.

-
-
gif, vtkbool

Output-mode flags passed to the simulation readers.

-
-
filterslist

Property filters used while loading each case.

-
-
scaleslist[str]

Scale factor applied to each variable.

-
-
mass, mass_alllist[str]

Mass variables and all supported mass-related variables.

-
-
caprocklist[str]

Supported caprock-integrity variables.

-
-
stressfloat

Vertical stress coefficient used for caprock quantities.

-
-
filtersslist[str]

Filter expressions applied while reading exported quantities.

-
-
-
-
Returns:
-
-
list[str]

Names of the generated PVD collection files.

-
-
-
-
-
- -
- - -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/py-modindex.html b/docs/py-modindex.html index ca0deff..8012eec 100644 --- a/docs/py-modindex.html +++ b/docs/py-modindex.html @@ -1,82 +1,442 @@ - - - - - - Python Module Index — plopm documentation - - - - - - - - - - - + + + + + + + + Python Module Index — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + +
+
+ + + + + + +
+ + + + -
- -
- + +
+ + + + + + + + - + + \ No newline at end of file diff --git a/docs/related.html b/docs/related.html index c7ba791..e6c6b5e 100644 --- a/docs/related.html +++ b/docs/related.html @@ -1,167 +1,674 @@ - - - - - - - Related — plopm documentation - - - - - - - - - - - + + + + + + + + + Related projects — plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + - -
- - -
- - -
+ + + +
+
+ + + + +
+ + + + + + + + + - Built with Sphinx using a - theme - provided by Read the Docs. - - -
-
+ +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + +
+
+ +
+ +
+
+ + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/search.html b/docs/search.html index 42cd482..66116dc 100644 --- a/docs/search.html +++ b/docs/search.html @@ -1,127 +1,528 @@ - - - - - - Search — plopm documentation - - - - - - - - - - - - - - + + + + + + + Search - plopm documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - -
- - -
- -
-
-
-
    -
  • - -
  • -
  • + + + - + + + + -
    +
    + + -
-
-
- -
- + +
+ + +
+
+ +
+ + +
+

Search

+ + + +
- + + + + + +
+ +
+
+
+ +
+ + + + +
+
+ +
+ +
+ + + + + + + +
+ - +
+ \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js index a2b39e5..d700625 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"alltitles":{"About plopm":[[0,null]],"Argument syntax":[[6,"argument-syntax"]],"Axes, coordinates, and formatting":[[6,"axes-coordinates-and-formatting"]],"Basic usage":[[6,"basic-usage"]],"Binary packages":[[5,"binary-packages"]],"Brew formula for macOS":[[5,"brew-formula-for-macos"]],"Caprock integrity":[[3,"caprock-integrity"]],"Color scales and styling":[[6,"color-scales-and-styling"]],"Colormaps":[[3,"colormaps"]],"Command-line interface":[[6,"command-line-interface"]],"Computation and data transformation":[[6,"computation-and-data-transformation"]],"Concept":[[6,"concept"]],"Contribute to the software":[[2,"contribute-to-the-software"]],"Contributing":[[2,null]],"Convert to VTK":[[3,"convert-to-vtk"]],"Different input files and ensembles":[[3,"different-input-files-and-ensembles"]],"Examples":[[3,null]],"Figure and subplot layout":[[6,"figure-and-subplot-layout"]],"Filtering, masking, and thresholds":[[6,"filtering-masking-and-thresholds"]],"Filters":[[3,"filters"]],"GIF and mask":[[3,"gif-and-mask"]],"GIF output":[[6,"gif-output"]],"Generic deck":[[3,"generic-deck"]],"Graphical abstract":[[3,"graphical-abstract"]],"Ground Rules":[[2,"ground-rules"]],"Hello world":[[3,"hello-world"]],"Histograms":[[3,"histograms"]],"Indices and tables":[[4,"indices-and-tables"]],"Information and diagnostics":[[6,"information-and-diagnostics"]],"Input and data selection":[[6,"input-and-data-selection"]],"Installation":[[5,null]],"Introduction":[[6,null]],"Module contents":[[8,"module-plopm"],[9,"module-plopm.config"],[11,"module-plopm.core"],[13,"module-plopm.utils"]],"OPM Flow":[[5,"opm-flow"]],"Option reference":[[6,"option-reference"]],"Output options":[[6,"output-options"]],"Plot types and statistical representation":[[6,"plot-types-and-statistical-representation"]],"Projections and subfigures":[[3,"projections-and-subfigures"]],"Python package":[[5,"python-package"]],"Reading from csv files":[[3,"reading-from-csv-files"]],"Rel perms and capillary pressure":[[3,"rel-perms-and-capillary-pressure"]],"Related":[[21,null]],"Reporting issues or problems":[[2,"reporting-issues-or-problems"]],"Rotation, translation, and zoom":[[3,"rotation-translation-and-zoom"]],"Seek support":[[2,"seek-support"]],"Source build in Linux/Windows":[[5,"source-build-in-linux-windows"]],"Source build in macOS":[[5,"source-build-in-macos"]],"Spatial and temporal selection":[[6,"spatial-and-temporal-selection"]],"Submodules":[[9,"submodules"],[11,"submodules"],[13,"submodules"]],"Subpackages":[[8,"subpackages"]],"Titles, labels, and legends":[[6,"titles-labels-and-legends"]],"VTK output":[[6,"vtk-output"]],"Welcome to plopm\u2019s documentation!":[[4,null]],"ad-micp":[[21,"ad-micp"]],"expreccs":[[21,"expreccs"]],"plopm":[[1,"plopm"],[7,null]],"plopm Python API":[[1,null]],"plopm package":[[8,null]],"plopm.config package":[[9,null]],"plopm.config.config module":[[10,null]],"plopm.core package":[[11,null]],"plopm.core.plopm module":[[12,null]],"plopm.utils package":[[13,null]],"plopm.utils.initialization module":[[14,null]],"plopm.utils.mapping module":[[15,null]],"plopm.utils.readers module":[[16,null]],"plopm.utils.terminal module":[[17,null]],"plopm.utils.write_oned module":[[18,null]],"plopm.utils.write_twod module":[[19,null]],"plopm.utils.write_vtk module":[[20,null]],"pofff":[[21,"pofff"]],"pycopm":[[21,"pycopm"]],"pymm":[[21,"pymm"]],"pyopmnearwell":[[21,"pyopmnearwell"]],"pyopmspe11":[[21,"pyopmspe11"]]},"docnames":["about","api","contributing","examples","index","installation","introduction","modules","plopm","plopm.config","plopm.config.config","plopm.core","plopm.core.plopm","plopm.utils","plopm.utils.initialization","plopm.utils.mapping","plopm.utils.readers","plopm.utils.terminal","plopm.utils.write_oned","plopm.utils.write_twod","plopm.utils.write_vtk","related"],"envversion":{"sphinx":66,"sphinx.domains.c":3,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":9,"sphinx.domains.index":1,"sphinx.domains.javascript":3,"sphinx.domains.math":2,"sphinx.domains.python":4,"sphinx.domains.rst":2,"sphinx.domains.std":2},"filenames":["about.rst","api.rst","contributing.rst","examples.rst","index.rst","installation.rst","introduction.rst","modules.rst","plopm.rst","plopm.config.rst","plopm.config.config.rst","plopm.core.rst","plopm.core.plopm.rst","plopm.utils.rst","plopm.utils.initialization.rst","plopm.utils.mapping.rst","plopm.utils.readers.rst","plopm.utils.terminal.rst","plopm.utils.write_oned.rst","plopm.utils.write_twod.rst","plopm.utils.write_vtk.rst","related.rst"],"indexentries":{},"objects":{"":[[8,0,0,"-","plopm"]],"plopm":[[9,0,0,"-","config"],[11,0,0,"-","core"],[13,0,0,"-","utils"]],"plopm.config":[[10,0,0,"-","config"]],"plopm.config.config":[[10,1,1,"","PlopmConfig"],[10,1,1,"","SimData"]],"plopm.config.config.PlopmConfig":[[10,2,1,"","aggregation"],[10,2,1,"","axis_grid"],[10,2,1,"","caprock_vars"],[10,2,1,"","case"],[10,2,1,"","case_labels"],[10,2,1,"","cases"],[10,2,1,"","cb_formats"],[10,2,1,"","clim"],[10,2,1,"","color_log"],[10,2,1,"","color_log_ticks"],[10,2,1,"","colorbar_format"],[10,2,1,"","colorbar_label"],[10,2,1,"","colorbar_position"],[10,2,1,"","colorbar_tick_count"],[10,2,1,"","colorbar_ticks"],[10,2,1,"","colormaps"],[10,2,1,"","colors"],[10,2,1,"","colors_default"],[10,2,1,"","colors_raw"],[10,2,1,"","csv"],[10,2,1,"","csv_column_summary"],[10,2,1,"","csv_columns"],[10,2,1,"","difference_input"],[10,2,1,"","disc_colormaps"],[10,2,1,"","discrete"],[10,2,1,"","distance"],[10,2,1,"","dpi"],[10,2,1,"","dual_grid"],[10,2,1,"","ensemble"],[10,2,1,"","equal_aspect"],[10,2,1,"","faults"],[10,2,1,"","fc"],[10,2,1,"","figsize"],[10,2,1,"","filename"],[10,2,1,"","fill_between_style"],[10,2,1,"","filters"],[10,2,1,"","fontsize"],[10,2,1,"","gif"],[10,2,1,"","gif_interval"],[10,2,1,"","gif_loop"],[10,2,1,"","global_range"],[10,2,1,"","grid_edges"],[10,2,1,"","hide_map_elements"],[10,2,1,"","histogram"],[10,2,1,"","inactive_color"],[10,2,1,"","layer"],[10,2,1,"","legend_labels"],[10,2,1,"","legend_location"],[10,2,1,"","linestyle"],[10,2,1,"","linestyle_default"],[10,2,1,"","linewidth"],[10,2,1,"","linewidth_values"],[10,2,1,"","list_variables"],[10,2,1,"","mask_threshold"],[10,2,1,"","mask_variable"],[10,2,1,"","mass_fracs"],[10,2,1,"","mass_vars"],[10,2,1,"","max_threshold"],[10,2,1,"","min_threshold"],[10,2,1,"","ncolors"],[10,2,1,"","output_dir"],[10,2,1,"","png"],[10,2,1,"","remove_duplicate_labels"],[10,2,1,"","restart"],[10,2,1,"","rotation"],[10,2,1,"","rst_range"],[10,2,1,"","scale_factor"],[10,2,1,"","sensor"],[10,2,1,"","slice"],[10,2,1,"","slice_mode"],[10,2,1,"","step_plot"],[10,2,1,"","stress_coefficient"],[10,2,1,"","subplot_grid"],[10,2,1,"","summary"],[10,2,1,"","summary_mass"],[10,2,1,"","suptitle"],[10,2,1,"","time"],[10,2,1,"","time_units"],[10,2,1,"","title"],[10,2,1,"","translation"],[10,2,1,"","units"],[10,2,1,"","variables"],[10,2,1,"","vsum"],[10,2,1,"","vtk"],[10,2,1,"","vtk_format"],[10,2,1,"","vtk_names"],[10,2,1,"","wells"],[10,2,1,"","xformat"],[10,2,1,"","xlabel"],[10,2,1,"","xlim"],[10,2,1,"","xlog"],[10,2,1,"","xscale"],[10,2,1,"","xtick_count"],[10,2,1,"","xunit"],[10,2,1,"","xunits"],[10,2,1,"","yformat"],[10,2,1,"","ylabel"],[10,2,1,"","ylim"],[10,2,1,"","ylog"],[10,2,1,"","yscale"],[10,2,1,"","ytick_count"],[10,2,1,"","yunit"],[10,2,1,"","yunits"]],"plopm.config.config.SimData":[[10,2,1,"","active_idx"],[10,2,1,"","active_pv"],[10,2,1,"","dx"],[10,2,1,"","dy"],[10,2,1,"","dz"],[10,2,1,"","grid"],[10,2,1,"","init"],[10,2,1,"","ncells"],[10,2,1,"","nsteps"],[10,2,1,"","nx"],[10,2,1,"","ny"],[10,2,1,"","nz"],[10,2,1,"","porv"],[10,2,1,"","steps"],[10,2,1,"","times"],[10,2,1,"","unrst"]],"plopm.core":[[12,0,0,"-","plopm"]],"plopm.core.plopm":[[12,3,1,"","__parse_number_list"],[12,3,1,"","_check_cmdargs"],[12,3,1,"","_load_parser"],[12,3,1,"","_parse_number"],[12,3,1,"","main"]],"plopm.utils":[[14,0,0,"-","initialization"],[15,0,0,"-","mapping"],[16,0,0,"-","readers"],[17,0,0,"-","terminal"],[18,0,0,"-","write_oned"],[19,0,0,"-","write_twod"],[20,0,0,"-","write_vtk"]],"plopm.utils.initialization":[[14,3,1,"","_find_all_cases"],[14,3,1,"","_find_first_case"],[14,3,1,"","_join_block_vars"],[14,3,1,"","build_config"],[14,3,1,"","init_maps"],[14,3,1,"","init_summary"],[14,3,1,"","is_summary"],[14,3,1,"","mass_unit"],[14,3,1,"","spatial_unit"]],"plopm.utils.mapping":[[15,3,1,"","get_xy_slice"],[15,3,1,"","get_xz_slice"],[15,3,1,"","get_yz_slice"],[15,3,1,"","map_xy"],[15,3,1,"","map_xz"],[15,3,1,"","map_yz"],[15,3,1,"","transform_grid"]],"plopm.utils.readers":[[16,3,1,"","_aggregate"],[16,3,1,"","_apply_filter"],[16,3,1,"","_apply_operator"],[16,3,1,"","_compute_distance"],[16,3,1,"","_find_keyword"],[16,3,1,"","_get_caprock"],[16,3,1,"","_get_mass"],[16,3,1,"","_get_saturation"],[16,3,1,"","_grid_indices"],[16,3,1,"","_read_histogram"],[16,3,1,"","_read_values"],[16,3,1,"","_resolve_var"],[16,3,1,"","_select_mass"],[16,3,1,"","get_faults"],[16,3,1,"","get_unit"],[16,3,1,"","get_wells"],[16,3,1,"","get_xy_coords"],[16,3,1,"","get_xz_coords"],[16,3,1,"","get_yz_coords"],[16,3,1,"","read_case"],[16,3,1,"","read_csv_grid"],[16,3,1,"","read_quantity"],[16,3,1,"","read_series"],[16,3,1,"","time_unit"]],"plopm.utils.terminal":[[17,1,1,"","PlopmHelpFormatter"],[17,3,1,"","_colorize"],[17,3,1,"","_supports_color"],[17,3,1,"","cli_current_value"],[17,3,1,"","cli_deprecated_value"],[17,3,1,"","cli_error_value"],[17,3,1,"","cli_info_value"],[17,3,1,"","plopm_error"],[17,3,1,"","plopm_info"],[17,3,1,"","plopm_name"],[17,3,1,"","plopm_success"],[17,3,1,"","plopm_tip"],[17,3,1,"","plopm_warning"],[17,3,1,"","warn_deprecated_options"]],"plopm.utils.terminal.PlopmHelpFormatter":[[17,4,1,"","_format_action_invocation"]],"plopm.utils.write_oned":[[18,3,1,"","_clean_name"],[18,3,1,"","_get_deck_name"],[18,3,1,"","_get_label"],[18,3,1,"","_plot_ensemble"],[18,3,1,"","_save_summary_csv"],[18,3,1,"","_save_summary_png"],[18,3,1,"","_set_formatted_ticks"],[18,3,1,"","_update_limits"],[18,3,1,"","make_plots"]],"plopm.utils.write_twod":[[19,3,1,"","_add_label"],[19,3,1,"","_add_map_overlay"],[19,3,1,"","_apply_diff_and_log"],[19,3,1,"","_case_name"],[19,3,1,"","_clean_name"],[19,3,1,"","_create_figure"],[19,3,1,"","_delete_extra_axes"],[19,3,1,"","_draw_frame"],[19,3,1,"","_draw_map"],[19,3,1,"","_formatted_ticks"],[19,3,1,"","_get_clim"],[19,3,1,"","_get_masks"],[19,3,1,"","_map_values"],[19,3,1,"","_normalize_axis"],[19,3,1,"","_prepare_colorbars"],[19,3,1,"","_prepare_map"],[19,3,1,"","_remove_colorbar"],[19,3,1,"","_save_animation"],[19,3,1,"","_save_map"],[19,3,1,"","_set_axis"],[19,3,1,"","_set_axis_ticks"],[19,3,1,"","_update_color_range"],[19,3,1,"","make_maps"]],"plopm.utils.write_vtk":[[20,3,1,"","_check_integer_conversion"],[20,3,1,"","_format_vtk_array"],[20,3,1,"","_vtk_flags"],[20,3,1,"","_warn_once"],[20,3,1,"","_write_pvd"],[20,3,1,"","_write_vtk_data"],[20,3,1,"","make_vtks"]]},"objnames":{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","attribute","Python attribute"],"3":["py","function","Python function"],"4":["py","method","Python method"]},"objtypes":{"0":"py:module","1":"py:class","2":"py:attribute","3":"py:function","4":"py:method"},"terms":{"0314fc":3,"0f":3,"0pressur":3,"1e":[3,6],"1e3":3,"1e6":3,"1f":[3,6],"2d":6,"2e":6,"2f":[3,6],"3d":6,"51c":3,"5e":3,"7274b3":3,"8mish":3,"A":[20,21],"About":4,"All":3,"An":[2,6,21],"At":6,"Below":[3,21],"Both":10,"By":[3,6],"Each":18,"For":[0,3,5,6],"From":3,"Here":3,"If":[3,5,12],"In":[2,3,6],"It":[3,12,18],"Most":10,"No":3,"The":[1,2,3,5,6,12,14,15,16,17,18,19,20],"Then":[3,5],"These":3,"This":[3,6,12,19],"To":[3,5],"We":2,"While":5,"You":[3,5],"_2":3,"__parse_number_list":[8,11,12],"_add_label":[8,13,19],"_add_map_overlay":[8,13,19],"_aggreg":[8,13,16],"_apply_diff_and_log":[8,13,19],"_apply_filt":[8,13,16],"_apply_oper":[8,13,16],"_array_lik":[],"_build":2,"_case_nam":[8,13,19],"_check_cmdarg":[8,11,12],"_check_integer_convers":[8,13,20],"_clean_nam":[8,13,18,19],"_color":[8,13,17],"_compute_dist":[8,13,16],"_create_figur":[8,13,19],"_delete_extra_ax":[8,13,19],"_draw_fram":[8,13,19],"_draw_map":[8,13,19],"_find_all_cas":[8,13,14],"_find_first_cas":[8,13,14],"_find_keyword":[8,13,16],"_format_action_invoc":[13,17],"_format_vtk_array":[8,13,20],"_formatted_tick":[8,13,19],"_get_caprock":[8,13,16],"_get_clim":[8,13,19],"_get_deck_nam":[8,13,18],"_get_label":[8,13,18],"_get_mask":[8,13,19],"_get_mass":[8,13,16],"_get_satur":[8,13,16],"_grid_indic":[8,13,16],"_io":17,"_join_block_var":[8,13,14],"_load_pars":[8,11,12],"_map_valu":[8,13,19],"_normalize_axi":[8,13,19],"_parse_numb":[8,11,12],"_plot_ensembl":[8,13,18],"_prepare_colorbar":[8,13,19],"_prepare_map":[8,13,19],"_read_histogram":[8,13,16],"_read_valu":[8,13,16],"_remove_colorbar":[8,13,19],"_resolve_var":[8,13,16],"_save_anim":[8,13,19],"_save_map":[8,13,19],"_save_summary_csv":[8,13,18],"_save_summary_png":[8,13,18],"_scalarmapp":19,"_select_mass":[8,13,16],"_set_axi":[8,13,19],"_set_axis_tick":[8,13,19],"_set_formatted_tick":[8,13,18],"_supports_color":[8,13,17],"_type":[],"_update_color_rang":[8,13,19],"_update_limit":[8,13,18],"_vtk_flag":[8,13,20],"_warn_onc":[8,13,20],"_write_pvd":[8,13,20],"_write_vtk_data":[8,13,20],"_z":3,"a8d8e3":3,"abil":3,"abov":3,"abstract":4,"accept":[2,6,12],"accord":15,"achiav":3,"achiev":3,"across":10,"act":6,"action":[2,5,17],"activ":[3,5,10,15,16,19],"active_idx":[9,10],"active_pv":[9,10],"ad":4,"add":[3,5,19],"addit":[3,6],"ag":[3,6],"agg":[3,6],"aggreg":[6,9,10,12,15,16],"ahiev":3,"alias":17,"allow":[3,6],"along":[3,10],"alpha":6,"alreadi":[19,20],"also":[2,3,5,6,18],"altern":2,"alway":17,"ampersand":6,"anaconda":5,"analys":2,"analysi":2,"angl":[6,10],"ani":[2,3,6,19],"anim":[6,10,12,16,19],"annot":19,"anoth":5,"ansi":17,"answer":2,"api":4,"appear":6,"appli":[3,6,10,14,15,16,17,19,20],"applic":3,"approach":[0,2,3,6],"appropri":12,"apt":5,"argpars":[12,14,17],"argument":[3,4,12,14,17],"argumentdefaultshelpformatt":17,"argv":[12,17],"arithmet":[3,6,15,16],"arrang":19,"array":[10,18,19,20],"artist":19,"ascii":20,"asp":[3,6],"aspect":6,"assign":[10,15,19],"associ":[10,19],"assum":3,"attribut":10,"auto":2,"automat":6,"avail":[3,5,6,10,12,14],"averag":[3,6],"ax":6,"axe":[3,4,10,18,19],"axes_divid":19,"axes_grid1":19,"axesdivid":19,"axi":[3,6,10,15,16,18,19],"axis_grid":[9,10],"axis_nam":[18,19],"b":[3,6],"b6c406":3,"background":[3,6],"backward":6,"bak":3,"band":[6,10,18],"bar":3,"base":[3,6,10,16,17,21],"basenam":18,"basetemp":2,"basic":4,"becaus":10,"befor":[2,10,19],"belong":19,"benchmark":[3,21],"besid":19,"best":6,"beyond":3,"big":3,"bin":[3,5,6,10],"binari":[2,4],"black":[2,3,6],"block":14,"bool":[10,14,16,17,18,19,20],"border":6,"bottom":6,"bound":[3,10,18],"boundari":10,"bracket":6,"branch":5,"brew":4,"brine":3,"build":[2,3,4,6,12,14,15,16,20],"build_config":[8,13,14],"build_opm_mpi":5,"built":5,"bwpr":[3,6],"c":[3,6],"cach":19,"calcit":21,"calcul":10,"call":3,"callback":19,"caller":12,"can":[2,3,5,6,10,12],"capillari":4,"caprock":[4,10,16,20],"caprock_list":16,"caprock_var":[9,10],"case":[3,6,9,10,14,16,18,19,20],"case_label":[9,10],"categor":19,"categori":[10,15],"cb":19,"cb_format":[9,10],"cbf":[3,6],"cbl":[3,6],"cbn":[3,6],"cbp":[3,6],"cbt":[3,6],"cc":[3,6],"ccs":3,"cd":5,"cddb6e":3,"cell":[3,6,10,12,15,16,19,20],"center":[0,3,6],"cet_cwr":3,"cet_glasbey_bw":3,"cfd":21,"cfg":[14,15,16,18,19],"challeng":0,"chang":[2,3],"changer":3,"changu":3,"check":[2,5,12,17,21],"checker":2,"checkout":5,"choic":12,"ci":[2,5],"cl":[3,6],"class":[10,17],"classif":10,"cli":[10,12,14,17,20],"cli_current_valu":[8,13,17],"cli_deprecated_valu":[8,13,17],"cli_error_valu":[8,13,17],"cli_info_valu":[8,13,17],"clim":[6,9,10],"clog":[3,6],"clone":[3,5],"clt":6,"cm":[5,6,19],"cmake":5,"cmax":19,"cmdarg":[12,14],"cmin":19,"co":3,"co2":[3,6,16,21],"co2_d":16,"co2_g":16,"co2m":[3,6],"code":[2,5,8,9,10,14,16,17],"coeffici":[6,10,16,20],"collabor":2,"collect":20,"color":[3,4,9,10,17,19],"color_log":[9,10],"color_log_tick":[9,10],"colorbar":[3,6,10,14,19],"colorbar_format":[9,10],"colorbar_index":19,"colorbar_label":[9,10],"colorbar_posit":[9,10],"colorbar_tick":[9,10],"colorbar_tick_count":[9,10],"colorcet":3,"colormap":[4,6,9,10,14],"colors_default":[9,10],"colors_raw":[9,10],"colour":19,"column":[3,6,10,16,19],"com":[3,5,6],"combin":[3,6,12],"comma":[3,6,12,14],"command":[3,4,5,10,12,14,17,20],"commit":2,"common":[3,5],"compar":3,"comparison":[3,16],"compat":[6,19],"complet":[6,12,16],"compon":[3,6,10,16,19],"comput":[3,4,16],"concept":4,"condit":[3,6,16,20],"config":[1,7,8],"configur":[3,6,10,12,14,15,16,18,19,20],"connect":3,"consid":[3,14],"consist":10,"construct":[16,19],"contain":[1,6,10,16,17,18,19],"content":[1,2,4,7],"continu":6,"contribut":[0,4,5],"control":[6,10,16,19],"conveni":6,"convers":[14,16,20],"convert":[4,5,6,10,12,14,16,18,19,20],"coordin":[3,4,10,12,14,15,16,18,19],"copi":[2,5],"core":[1,7,8],"corner":3,"correspond":[3,6,16],"count":[6,10],"cov":2,"cover":20,"cp":3,"cpus":3,"creat":[2,3,5,6,10,12,16,18,19,20],"csp":21,"cssr":[0,3,5,6],"csv":[4,6,9,10,12,16,18,19],"csv_col":10,"csv_column":[9,10],"csv_column_summari":[9,10],"csvs":3,"cubehelix":3,"curl":3,"current":[5,6,10,17,18,19],"current_directori":5,"curv":3,"custom":[6,18,19],"cvs":16,"d":6,"dash":3,"data":[3,4,10,12,15,16,18,19,20],"dataarray":20,"dataclass":1,"date":[3,6,16,18],"day":[3,16],"dcmake_build_typ":5,"decim":20,"decis":14,"deck":[4,16,19],"deck_flow_data":3,"deckd":19,"deckn":18,"dedic":5,"default":[3,6,10,14,15,16,17,18,19,20],"defcol":19,"defin":[3,14,18],"definit":3,"degre":[6,10],"delay":10,"deleg":19,"delet":3,"depend":[2,5,10,18],"deprec":17,"deriv":[10,16,18],"describ":[2,3,6],"descript":19,"detect":10,"determin":[14,17,19],"dev":[2,5],"develop":5,"deviat":18,"dg":6,"di":[3,6],"diagnost":4,"diffa":19,"differ":[1,4,6,10,12,14,19],"difference_input":[9,10],"dimens":[3,10,15,16,19],"dimension":[10,12,14,15,16,18,19],"dir":6,"direct":[3,6,15],"directori":[6,10,17,19,20],"disabl":[6,17],"disc_colormap":[9,10],"discov":14,"discret":[6,9,10],"dism":6,"dispatch":[12,19],"disperc":3,"display":[6,10,14,15,16,17,18,19],"dissa":3,"dissolv":[3,16],"dist":6,"distanc":[6,9,10,12,16],"distribut":[3,6],"divid":19,"dname":20,"doc":2,"docs_al":3,"docs_caprock_integr":3,"docs_colormap":3,"docs_convert_to_vtk":3,"docs_different_files_and_ensembl":3,"docs_filt":3,"docs_generic_deck":3,"docs_gif_mask":3,"docs_graphical_abstract":3,"docs_hello_world":3,"docs_histogram":3,"docs_projections_subfigur":3,"docs_reading_csv":3,"docs_rel_perms_and_capillary_pressur":3,"docs_rotation_translation_zoom":3,"document":[2,3,5,6],"done":5,"dot":[3,6],"download":[3,5],"downstream":10,"dpi":[3,6,9,10],"drainag":3,"draw":[10,18,19],"draw_map":19,"drawn":10,"dri":3,"dtype":20,"dual":[6,10,15],"dual_grid":[9,10],"dumb":17,"duplic":6,"dure":[10,19],"duse_mpi":5,"dvipng":5,"dwith_ndebug":5,"dx":[9,10],"dy":[9,10],"dynam":[3,6,21],"dz":[9,10],"e":[3,5,6],"earlier":6,"easier":6,"eclfil":[10,16],"edg":[5,6,10],"egrid":[3,5,10,16],"either":5,"element":6,"els":5,"elsewher":16,"em":21,"email":2,"emit":20,"empti":[3,6,14,19],"en":[3,6],"enabl":[3,6,10,15],"enclos":6,"encod":17,"end":[3,6],"engin":19,"ensembl":[4,6,9,10,18],"enterpris":5,"entir":6,"entri":[3,6,12],"environ":5,"equal":6,"equal_aspect":[9,10],"error":[6,12,17],"erst":[10,16],"esf":6,"estim":3,"evalu":[10,16],"ex":3,"exampl":[2,4,6],"example0":3,"example3_form":3,"exclud":[17,18],"exclus":12,"execut":[1,2,3,5,6,17],"exist":5,"expand":[3,14],"expected_length":12,"explicit":[10,14,18],"export":[10,12,20],"exprecc":4,"express":[10,14,16,18,19,20],"extend":[2,3],"extens":[6,16,18,19],"extent":19,"extinf":19,"extra":5,"extract":10,"f":6,"face":[10,19],"facecolor":6,"faci":3,"factor":[6,10,14,16,19,20],"factori":10,"fail":16,"fals":[10,19],"familiar":[2,3],"fatal":17,"fault":[3,6,9,10,12,15,16,19],"fb":6,"fc":[6,9,10],"fc035a":3,"featur":[0,10,15,19],"feature_id":[15,19],"fewer":3,"fffa86":3,"fgip":[3,6],"fgipm":6,"fgmip":3,"fi":5,"field":[3,6,10],"fig":[18,19],"figsiz":[6,9,10],"figur":[3,4,5,10,12,18,19],"file":[2,4,5,6,10,12,14,16,17,18,19,20],"filenam":[6,9,10,15,17,18,19],"fill":6,"fill_between_styl":[9,10],"filter":[4,9,10,16,20],"filterss":20,"final":[10,19],"find":[14,16],"finit":[16,19,20],"fipnum":[3,6],"first":[3,6,14,18],"fix":2,"flag":[3,10,20],"flatten":[15,20],"flexibl":6,"float":[3,10,12,14,16,18,19,20],"float16":[3,6],"float32":[3,6],"float64":[3,6,16],"flore":3,"flow":[2,3,4,6,12,15,16,20,21],"flt":[3,6],"fluid":6,"fluidflow":21,"fluxnum":6,"fn":[3,6],"folder":[1,2,3,5,10,14],"follow":[3,5,6,10],"font":[3,5,6,10],"fontsiz":[6,9,10],"fork":[0,2],"form":[6,10],"format":[2,3,4,5,10,14,16,17,18,19,20],"formatt":17,"formula":4,"forth":3,"found":14,"four":6,"fp":6,"fraction":[3,10,16],"frame":[6,10,19],"framework":[6,21],"free":[6,16],"front":3,"fs":[3,6],"full":[6,10],"funcanim":19,"function":[3,10,12,14,18],"fund":0,"futur":3,"fwcdm":6,"fz":[3,6],"g":[3,5,6],"game":3,"gas":[3,6,16],"gasm":6,"ge":[3,6],"general":[3,6,20],"generat":[2,3,6,10,12,14,17,18,19,20],"generated_fil":19,"generic":4,"geolog":[6,21],"geometri":[10,12,15,19,20],"get":[2,3,5,14,16,18,19],"get_fault":[8,13,16],"get_unit":[8,13,16],"get_wel":[8,13,16],"get_xy_coord":[8,13,16],"get_xy_slic":[8,13,15],"get_xz_coord":[8,13,16],"get_xz_slic":[8,13,15],"get_yz_coord":[8,13,16],"get_yz_slic":[8,13,15],"gi":[3,6],"gif":[4,9,10,12,16,19,20],"gif_interv":[9,10],"gif_loop":[9,10],"gigatonn":0,"git":[3,5],"github":[2,3,5,6],"githubusercont":3,"give":3,"given":[3,6],"gl":[3,6],"global":[6,10,16],"global_rang":[9,10],"gr":[3,6],"gradient":17,"graphic":[4,17],"grid":[3,5,6,9,10,12,15,16,18,19,20],"grid_edg":[9,10],"ground":4,"group":[6,10,15,16,18,19,20],"gui":3,"h":[3,6],"h2hysteresi":3,"h2o":3,"h2o_l":16,"h2o_v":16,"h2om":6,"half":10,"hand":16,"handl":[1,10,18],"harmon":[6,15],"hashabl":20,"hat":5,"head":3,"height":[6,10],"hello":4,"help":[2,3,5,6,17],"hex":3,"hidden":[10,19],"hide":[3,6,17],"hide_map_el":[9,10],"higher":3,"hist":[3,6],"histogram":[4,6,9,10,12,16],"histori":21,"home":6,"homebrew":5,"host":6,"howev":3,"hpc":0,"html":2,"https":[3,5,6],"human":19,"hydrogen":3,"hysteresi":3,"ic":6,"identifi":[14,20],"ignor":2,"ilustr":3,"im_ani":19,"imag":[19,21],"imbibit":3,"implement":12,"import":2,"inact":[6,10,16],"inactive_color":[9,10],"inc":18,"inch":6,"includ":[3,5,6,10,15,16,17,18,19,20],"incompat":12,"increas":3,"indefinit":6,"indent":20,"indent_incr":17,"index":[4,10,15,16,18,19,20],"index_i":16,"index_j":16,"index_k":[3,16],"indic":[6,10,14,16,19],"individu":3,"induc":21,"inferno":3,"inform":[3,4,17],"init":[3,5,9,10,12,16,20],"init_map":[8,13,14],"init_summari":[8,13,14],"initi":[3,6,8,10,13,15,16,18,19],"inj":3,"inject":3,"input":[4,14,16,19,20],"insert":20,"insid":[3,5],"inspect":[6,17,20],"instal":[2,3,4],"instead":[6,10,12],"instruct":5,"int":[10,12,15,16,18,19,20],"int16":6,"int32":6,"int64":6,"int8":6,"integ":20,"integr":[4,10,16,20],"interact":[3,6,17],"interest":[3,5,21],"interfac":[3,4],"interim":5,"interpol":18,"intersect":16,"interval":[6,15,16],"introduct":4,"invalid":[12,17,18],"invoc":17,"is_summari":[8,13,14],"isgif":16,"issu":[0,4],"iter":19,"j":[6,10,15],"j5":5,"jet":[3,6],"job":20,"join":6,"just":3,"k":[3,6,10,15,19,20],"k_r":3,"keep":19,"key":20,"key_low":16,"key_up":16,"keyword":16,"kg":3,"kilogram":[3,14],"kiloton":3,"kilotonn":3,"km":[3,6],"krg":[3,6],"krg1":3,"krg2":3,"krg3h":3,"krgh":3,"krog":[3,6],"krow":[3,6],"krw":[3,6],"krw1":3,"krw2":3,"krwh":3,"kt":3,"l":[3,5],"label":[3,4,10,14,15,16,17,18,19],"label_index":19,"label_nam":19,"larg":3,"larger":3,"last":[3,6,19],"lateral":[3,6],"latex":5,"layer":[3,9,10,12],"layout":[4,10,17,18,19],"lead":3,"leakag":21,"least":[3,6],"left":[3,6,16],"legaci":6,"legend":[3,4,10,18],"legend_label":[9,10],"legend_loc":[9,10],"length":12,"let":3,"level":[10,12],"librari":5,"like":[3,14],"limipr":[3,6],"limit":[3,6,10,14,18,19],"line":[2,3,4,5,10,12,14,17],"linestyl":[6,9,10],"linestyle_default":[9,10],"linewidth":[6,9,10],"linewidth_valu":[9,10],"lint":5,"linux":4,"liqm":6,"liquid":[3,16],"list":[6,10,12,14,15,16,17,18,19,20],"list_vari":[9,10],"literatur":3,"ll":[3,6],"llb":[3,6],"load":[10,15,16,19,20],"local":[2,3],"locat":[1,3,6,10,16,17,18,19],"log":[3,6],"logarithm":[6,10,18,19],"lognorm":[3,6],"long":6,"look":[2,3],"loop":6,"lower":[3,6,10,18],"lowercas":[18,19],"ls":[3,6],"lv":[3,6],"lw":[3,6],"m":[3,5,6],"machin":5,"maco":4,"macport":5,"mactex":5,"main":[1,2,3,8,11,12],"maintain":2,"major":10,"make":[2,3,5,6],"make_map":[8,13,19],"make_plot":[8,13,18],"make_vtk":[8,13,20],"mamba":5,"manag":5,"mani":6,"mantain":2,"manual":3,"map":[3,6,8,10,12,13,14,16,19],"map_index":19,"map_xi":[8,13,15],"map_xz":[8,13,15],"map_yz":[8,13,15],"mappabl":19,"mask":[4,10,12,19],"mask_threshold":[9,10],"mask_vari":[9,10],"maska":19,"mass":[3,6,10,14,16,20],"mass_al":[16,20],"mass_frac":[9,10],"mass_unit":[8,13,14],"mass_var":[9,10],"master":5,"match":[14,21],"matplotlib":[3,6,10,14,16,18,19],"max":[3,6],"max_help_posit":17,"max_t":18,"max_threshold":[9,10],"max_v":18,"maxima":19,"maximum":6,"may":6,"mean":[3,6,18],"member":10,"merg":2,"mesh":[15,16,19],"messag":[12,17,20],"metadata":16,"method":[1,6,10,16],"metr":14,"micp":4,"microbi":21,"microsystem":21,"middl":[3,6],"might":[2,5,21],"million":3,"millisecond":6,"min":6,"min_t":18,"min_threshold":[9,10],"min_v":18,"miniforg":5,"minim":20,"minima":19,"minimum":6,"miss":[2,16],"mkdir":5,"mm":6,"mode":[3,6,10,12,16,17,20],"model":[3,6,10,20,21],"modifi":[5,6],"modul":[1,4,7,21],"motiv":3,"mpi":[3,5],"mpirun":3,"mpl_toolkit":19,"mskl":14,"mt":6,"multipl":6,"multipli":[3,10],"must":[3,6],"mutabl":10,"mutual":12,"mv":[3,6],"mx":[15,19],"mypi":2,"n":[2,15,16,19],"n_s":19,"name":[3,6,10,12,15,16,17,18,19,20],"name_index":18,"namespac":[12,14],"nan":[3,16,18],"ncell":[9,10],"ncolor":[9,10],"ndarray":[10,15,16,18,19,20],"near":21,"need":[2,3,5,20],"negat":[3,20],"new":[0,2,3],"nice":[2,6],"no_color":17,"non":[3,10,17,18,20],"none":[10,12,14,15,16,17,18,19,20],"nonzero":19,"noreturn":17,"norm":[3,6],"normal":[6,10,14,16],"norn":3,"norne_atw2013":3,"norne_wel":3,"norne_wells_glob":3,"now":3,"np":[3,15,16,18,19,20],"nstep":[9,10],"ntot":16,"number":[0,3,6,10,12,19],"numer":[10,12,18,20],"numpi":20,"nx":[9,10,16],"ny":[9,10,16],"nz":[9,10,16],"o":[3,6],"object":[10,17,19],"objepr":[3,6],"obtain":3,"occurr":6,"omit":[10,17],"onc":[3,17,20],"one":[3,6,10,12,14,15,16,17,18,19,20],"onli":[3,6,10,17,20],"onlin":5,"onto":[15,19],"op":16,"opac":10,"open":[3,10,16,20,21],"oper":[10,12,16,18,19],"opm":[2,3,4,6,10,12,16,18,19,20,21],"opm1":3,"opm2":3,"opm3":3,"opm4":3,"opmfil":16,"opmrestart":16,"optim":3,"option":[3,4,5,10,12,14,15,16,17,18,19,20],"order":[3,6,10,15,16,19],"org":5,"origin":[3,17,19],"original_loc":19,"output":[3,4,5,10,12,14,16,17,18,19,20],"output_dir":[9,10,17],"outsid":[3,6,10,20],"overlay":19,"overpr":[3,6],"p":3,"p0":3,"p_c":3,"packag":[1,2,4,7],"pad":19,"page":[2,4],"pair":6,"paper":6,"paramet":[12,14,15,16,17,18,19,20],"paraview":[3,6],"pars":[10,12,14,16],"parser":[12,14],"part":6,"partial":14,"pascal":3,"pass":[6,20],"path":[3,6,10,14,16,18,19],"pcfact":6,"pcog":[3,6],"pcog5":3,"pcolormesh":6,"pcow":[3,6],"pcwg":[3,6],"per":[6,10,14,16,20],"perfor":3,"perm":4,"permeabl":[3,6,15],"permx":[3,6],"permz":[3,6],"phase":[3,16],"pip":[2,3,5],"place":[3,6,10,14,19],"placehold":[6,16],"placement":10,"plane":[3,6],"platform":5,"pleas":[0,2],"plopm":[2,3,5,6],"plopm_error":[8,13,17],"plopm_info":[8,13,17],"plopm_nam":[8,13,17],"plopm_success":[8,13,17],"plopm_tip":[8,13,17],"plopm_warn":[8,13,17],"plopmconfig":[8,9,10,14,15,16,18,19],"plopmhelpformatt":[8,13,17],"plot":[1,3,4,10,12,14,15,16,18,19],"png":[3,6,9,10,12,18,19],"pofff":4,"point":[3,12,16],"popul":[10,20],"pore":[3,6,10,15,16],"poro":[3,6],"poros":[3,6,10,15],"porv":[6,9,10,16],"posit":[6,10,19],"possibl":[2,3],"postprocess":6,"precipit":21,"prefer":[2,6],"prepar":[10,15,19],"prerequisit":5,"present":[3,6,19],"pressur":[4,6],"pressure_k5":6,"previous":[2,3,5],"primari":[6,10,14,19],"primarili":12,"print":[6,10],"problem":4,"process":[6,10,12,14],"profil":16,"prog":17,"program":17,"programmat":12,"progress":10,"project":[0,4,5,6,21],"properti":[3,6,10,12,14,15,16,19,20],"propos":18,"provid":[3,6,10],"prs":2,"pull":[0,2],"puor":3,"purpos":6,"push":2,"pushd":2,"pvd":[3,20],"pvmean":[6,16],"pwd":5,"py":3,"py314":2,"pycopm":[4,5],"pylint":2,"pymm":4,"pyopmnearwel":[3,4],"pyopmspe11":[3,4],"pyplot":6,"pytest":2,"python":[2,3,4,18,19,21],"python3":5,"qskl":16,"quaa":19,"quan":18,"quantiti":[3,6,10,14,16,19,20],"quick":6,"quot":[6,17],"r":[2,3,5,6],"r1_cart_10m":3,"r4_cp_8m":3,"rais":[0,2,12,17],"random":3,"rang":[3,6,10,19,20],"rate":3,"ratio":3,"raw":3,"rdl":[3,6],"reach":3,"read":[4,10,12,16,18,19,20],"read_cas":[8,13,16],"read_csv_grid":[8,13,16],"read_quant":[8,13,16],"read_seri":[8,13,16],"readabl":19,"reader":[8,10,13,14,20],"readi":20,"realiz":18,"receiv":[10,19],"recent":5,"recommend":5,"recurs":14,"red":5,"reduc":3,"ref":3,"refer":4,"region":[3,21],"regular":16,"rejoin":14,"rel":4,"relat":[3,4,10,20],"releas":[5,6],"reli":3,"remain":6,"remedi":21,"remov":[3,6,19],"remove_axi":19,"remove_duplicate_label":[9,10],"render":19,"rendit":17,"repeat":[6,10],"replac":[2,17,18,19],"repo":[2,5],"report":[3,4,10,12,16,17,20],"repositori":[2,5],"represent":4,"request":[0,2,6,10,12,14,16,18,19,20],"requir":[2,3,5,6,12,16,19],"resdata":3,"reservoir":[6,21],"residu":3,"resolut":[6,10,18,19],"resolv":16,"resourc":0,"respect":3,"restar":3,"restart":[3,6,9,10,14,16,19,20],"restart_index":19,"restor":19,"result":[3,6,12,16,18,19,20],"retain":[6,10,17,19],"return":[12,14,15,16,17,18,19,20],"review":2,"rgb":3,"rgmds":3,"right":[3,6,16],"rigth":3,"rise":2,"rm":3,"rock":3,"rot":[3,6],"rotat":[4,6,9,10,15],"routin":3,"row":[6,10,15,19],"rporv":[3,6],"rptrst":[3,6],"rst_rang":[9,10],"ruff":2,"rule":4,"run":[2,3,5,6,10,12,20],"runtim":[10,12,14],"s":[3,5,6],"s_w":3,"safe":[18,19],"sampl":3,"satnum":[3,6],"satur":[3,6,16],"save":[3,6,18,19,20],"save_index":19,"sc":[3,6],"scalarmapp":19,"scale":[3,4,10,14,16,19,20],"scale_factor":[9,10],"schedul":3,"script":[1,2,3,5,6],"search":[4,14],"second":[3,10],"section":3,"sed":3,"see":[2,3,5],"seek":4,"segment":16,"select":[3,4,10,12,14,15,16,17,18,19,20],"semicolon":6,"send":2,"sensor":[3,6,9,10,12,16],"separ":[3,6,12,14,18],"sequenc":[10,17],"seri":[6,10,12,14,16,18,20],"set":[3,6,10,14,15,16,18,19,20],"setuptool":5,"sf":[3,6],"sg":[3,6],"sgas":[3,6,16],"sh":[3,5],"share":[10,12,14,18,19],"short":6,"show":[3,6],"shown":[3,10,19],"simdata":[8,9,10,15,16,19,20],"simpli":[3,5],"simplifi":6,"simul":[0,3,5,6,10,12,14,16,18,19,20,21],"sinc":3,"singl":[2,3,6],"site":21,"six":2,"size":[3,6,10],"skip":[5,6,19],"slice":[6,9,10,12,14,15,16,19],"slice_mod":[9,10],"slice_nam":19,"slice_titl":19,"slide":[3,6],"slide_index":19,"slot":19,"smspec":16,"softwar":[0,4],"soil":16,"solid":[3,6],"solut":3,"soon":2,"sort":14,"sourc":[3,4,21],"sp":6,"space":[3,6,19],"spatial":[3,4,10,14,16,19],"spatial_unit":[8,13,14],"spe10_model2":3,"spe11":21,"spe11_opm1":3,"spe11_opm2":3,"spe11_opm3":3,"spe11_opm4":3,"spe11b":[3,6],"spe11b_higher_r":3,"spe11b_larger_inj":3,"spe11b_spatial_map_250i":3,"spe11b_spatial_map_500i":3,"spe11b_spatial_map_plopmi":3,"spe11b_time_seri":3,"spe11b_tun":6,"spe11c":3,"spe11c_0005":3,"special":[3,6,14],"specif":[5,6,10,12,18,19],"specifi":3,"spectral":3,"spring":3,"squash":2,"src":2,"st":[3,6],"standard":[10,17,18],"start":6,"state":[6,19],"static":[2,6,10,16],"statist":[4,18],"std":3,"stderr":17,"stem":[16,18,19,20],"step":[2,3,5,6,9,10,16,19,20],"step_plot":[9,10],"storag":[0,21],"store":[3,10,14,16],"str":[10,12,14,15,16,17,18,19,20],"stream":17,"stress":[3,6,10,16,20],"stress_coeffici":[9,10],"string":[10,14],"structur":6,"studi":21,"style":[3,4,10,14,17,18],"sub1":19,"subfigur":4,"submodul":[1,7,8],"subpackag":[1,4,7],"subplot":[3,4,10,18,19],"subplot_grid":[9,10],"subsurfac":0,"subsystem":5,"subtract":6,"succed":5,"succeed":[2,3],"sudo":5,"suffix":14,"suggest":17,"suitabl":10,"sum":6,"summari":[3,6,9,10,12,14,18],"summary_mass":[9,10],"summit":3,"super":5,"suppli":[6,10,19],"support":[3,4,5,6,10,12,16,17,18,20],"suptitl":[6,9,10],"sustain":0,"swat":16,"syntax":[4,12],"sys":[12,17],"systemexit":[12,17],"t":[3,6,19],"tab":20,"tab20c_r":3,"tabl":[3,6],"tabul":[12,14],"tabular":18,"tag":5,"tailor":21,"tap":5,"target":[2,10,16,19,20],"target_dtyp":20,"temp":3,"temperatur":3,"tempor":4,"term":[2,17],"termin":[3,5,8,13],"test":[2,3,5,12,16],"test_generic_deck":3,"test_output":2,"texliv":5,"text":[6,17,19],"textiowrapp":17,"thermal":20,"thick":15,"three":[3,6,12,15,19],"threshold":[4,10,16],"tick":[3,6,10,18,19],"time":[3,6,9,10,12,16,18,20],"time_unit":[8,9,10,13,16],"titl":[3,4,9,10],"tnrst":20,"token":16,"toml":3,"tool":[2,3,5,6,21],"top":[3,12],"total":[3,10],"tr":[3,6],"transform":[4,15,16,19],"transform_grid":[8,13,15],"translat":[4,6,9,10,15],"tri":[2,3,5],"true":[3,10,14,16,17],"truncat":20,"trust":5,"tstep":6,"tu":[3,6],"tug":5,"tunit":[16,18],"tupl":[10,14,15,16,18,19,20],"turbo":3,"turn":5,"tutori":2,"two":[1,3,6,12,15,19],"txt":[2,5],"type":[3,4,5,10,20],"u":3,"ubuntu":[2,5],"uint16":[3,6],"uint32":6,"uint64":6,"uint8":6,"unavail":[16,17,20],"uncertainti":10,"understand":6,"uniqu":20,"unit":[3,6,9,10,14,16,18,19],"unknown":14,"unless":17,"unrst":[3,5,9,10,12,16,20],"unsaf":20,"unscal":19,"unsign":20,"unus":19,"updat":[14,18,19],"upgrad":5,"upper":[3,6,10],"us":3,"usag":4,"use":[0,1,2,3,5,6,10,12,14,15,16,17,18,19,20,21],"use_csv":19,"user":[2,3,5,6,10,18],"utf":17,"util":[1,7,8,12],"v":[3,6],"v2026":5,"valid":12,"valu":[3,6,10,12,15,16,17,18,19,20],"value_format":[18,19],"vanimo":3,"vapm":6,"vapor":16,"var":[15,16,18,19,20],"var_index":[18,19],"variabl":[3,6,9,10,14,15,16,18,19,20],"vec":16,"vect":19,"vector":[3,6,10,12,14,18],"venv":5,"version":[2,3,5,8,9],"vertic":[10,15,16,20],"vf":[3,6],"via":[3,5],"view":3,"viridi":6,"virtual":5,"visit":2,"visual":[3,6],"vmax":[6,16],"vmin":[6,16],"vn":6,"volum":[3,6,10,15,16],"vplopm":5,"vsum":[9,10],"vtk":[4,5,9,10,12,14,16,20],"vtk_format":[9,10],"vtk_name":[9,10],"vtkformat":20,"vtkformat_list":20,"vtkname":20,"vtks":3,"vtu":[3,20],"w":[3,6,17],"warn":[17,20],"warn_deprecated_opt":[8,13,17],"warning_key":20,"water":16,"websit":3,"week":3,"weight":[6,15,16],"welcom":[0,2],"well":[2,3,6,9,10,12,15,16,19,21],"wheel":5,"whether":[10,14,16,17,18,19],"white":[3,6],"whole":6,"whose":[14,17],"width":[3,6,10,17],"will":[2,3],"window":4,"within":[6,10,18],"without":[3,14,16,18,19],"work":[2,5],"workflow":[10,12,14],"world":4,"wrap":17,"write":[3,5,18,19,20],"write_on":[8,13],"write_twod":[8,13],"write_vtk":[8,13],"written":[3,10,20],"www":5,"x":[3,6,15,16,18,19],"x_g_h2o":16,"x_l_co2":16,"x_n":3,"xc":[15,19],"xco2l":[3,6],"xco2v":6,"xf":[3,6],"xformat":[6,9,10],"xh2ol":6,"xh2ov":6,"xl":[3,6],"xlabel":[6,9,10],"xlim":[6,9,10],"xlog":[6,9,10],"xlow":18,"xname":19,"xnt":[3,6],"xscale":[9,10],"xtick":6,"xtick_count":[9,10],"xu":[3,6],"xunit":[6,9,10],"xy":[3,6,15,16],"xz":[3,15,16],"y":[3,5,6,15,16,18,19],"yc":[15,19],"year":3,"yf":[3,6],"yformat":[6,9,10],"yl":[3,6],"ylabel":[6,9,10],"ylim":[6,9,10],"ylog":[3,6,9,10],"ylow":18,"yml":[2,5],"yname":19,"ynt":[3,6],"yscale":[9,10],"ytick":6,"ytick_count":[9,10],"yu":[3,6],"yunit":[6,9,10],"yz":[15,16],"z":[3,16],"z_n":3,"zero":16,"zip":3,"zoom":4},"titles":["About plopm","plopm Python API","Contributing","Examples","Welcome to plopm\u2019s documentation!","Installation","Introduction","plopm","plopm package","plopm.config package","plopm.config.config module","plopm.core package","plopm.core.plopm module","plopm.utils package","plopm.utils.initialization module","plopm.utils.mapping module","plopm.utils.readers module","plopm.utils.terminal module","plopm.utils.write_oned module","plopm.utils.write_twod module","plopm.utils.write_vtk module","Related"],"titleterms":{"About":0,"abstract":3,"ad":21,"api":1,"argument":6,"axe":6,"basic":6,"binari":5,"brew":5,"build":5,"capillari":3,"caprock":3,"color":6,"colormap":3,"command":6,"comput":6,"concept":6,"config":[9,10],"content":[8,9,11,13],"contribut":2,"convert":3,"coordin":6,"core":[11,12],"csv":3,"data":6,"deck":3,"diagnost":6,"differ":3,"document":4,"ensembl":3,"exampl":3,"exprecc":21,"figur":6,"file":3,"filter":[3,6],"flow":5,"format":6,"formula":5,"generic":3,"gif":[3,6],"graphic":3,"ground":2,"hello":3,"histogram":3,"indic":4,"inform":6,"initi":14,"input":[3,6],"instal":5,"integr":3,"interfac":6,"introduct":6,"issu":2,"label":6,"layout":6,"legend":6,"line":6,"linux":5,"maco":5,"map":15,"mask":[3,6],"micp":21,"modul":[8,9,10,11,12,13,14,15,16,17,18,19,20],"opm":5,"option":6,"output":6,"packag":[5,8,9,11,13],"perm":3,"plopm":[0,1,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"plot":6,"pofff":21,"pressur":3,"problem":2,"project":3,"pycopm":21,"pymm":21,"pyopmnearwel":21,"pyopmspe11":21,"python":[1,5],"read":3,"reader":16,"refer":6,"rel":3,"relat":21,"report":2,"represent":6,"rotat":3,"rule":2,"s":4,"scale":6,"seek":2,"select":6,"softwar":2,"sourc":5,"spatial":6,"statist":6,"style":6,"subfigur":3,"submodul":[9,11,13],"subpackag":8,"subplot":6,"support":2,"syntax":6,"tabl":4,"tempor":6,"termin":17,"threshold":6,"titl":6,"transform":6,"translat":3,"type":6,"usag":6,"util":[13,14,15,16,17,18,19,20],"vtk":[3,6],"welcom":4,"window":5,"world":3,"write_on":18,"write_twod":19,"write_vtk":20,"zoom":3}}) \ No newline at end of file +Search.setIndex({"alltitles":{"-ag/--axis-grid <0|1>":[[45,"ag-axis-grid-0-1"]],"-agg/--aggregation ":[[36,"agg-aggregation-methods"]],"-asp/--equal-aspect <0|1>":[[35,"asp-equal-aspect-0-1"]],"-c/--colors ":[[45,"c-colors-colors"]],"-cbf/--colorbar-format ":[[45,"cbf-colorbar-format-format"]],"-cbl/--colorbar-label