diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5f35c8..516ed7b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,11 +1,12 @@ name: test on: - push: - branches: - - main - tags: "*" - pull_request: + push: + branches: + - main + tags: + - "*" + pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -19,19 +20,22 @@ jobs: matrix: python-version: ['3.11', '3.13'] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: test-requirements.txt - name: Install test-requirements - run: | - pip install -r test-requirements.txt + run: pip install -r test-requirements.txt - name: Run unit tests run: | - pytest ert/bin/scripts/fm_lgr.py ert/bin/scripts/fm_tracer_breakthrough.py # currently the only scripts with unit tests + pytest ert/bin/scripts/fm_lgr.py ert/bin/scripts/fm_tracer_breakthrough.py - name: Ruff format - run: | - ruff format --check + run: ruff format --check + + - name: Ruff check + run: ruff check . diff --git a/README.md b/README.md index 512ac49..fcdc75c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ push it, as the full size of it will stack up each time. This has the downside t latest commit(s) may have inconsistencies. For tagged versions however, RMS should always be at par with all other files. -Git LSF is used for storing the large binary files, so ensure you have it installed +Git LFS is used for storing the large binary files, so ensure you have it installed before cloning/pushing/pulling (one time install locally per user): ``` shell @@ -25,25 +25,25 @@ git lfs install ## Note -Since RMS is not fully integrated (we upload a zipped and archived version), PR's +Since RMS is not fully integrated (we upload a zipped and archived version), PRs involving RMS should be clarified with admins upfront, otherwise they are likely to be rejected. -Even if one do not have access to fully restore the project, cloning it could still be a -useful way of accessing model files, scripts, workflows, etc. +Even if one does not have access to fully restore the project, cloning it could still be +a useful way of accessing model files, scripts, workflows, etc. ## License -This work is dual-licensed under CC-BY-4.0 and GPL-3.0 (or any later version). Please +This work is dual-licensed under CC-BY-SA-4.0 and GPL-3.0 (or any later version). Please see the files LICENSE-CCBYSA and LICENSE-GPLV3 for full details. -Data and text files in this work is licensed under a +Data and text files in this work are licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License][cc-by-sa]. -Code (mostly python) in this work is licensed under a -[GNU General Public Version 3 Liense][gpl-v3]. +Code (mostly Python) in this work is licensed under the +[GNU General Public License Version 3][gpl-v3]. [![CC BY-SA 4.0][cc-by-sa-shield]][cc-by-sa] diff --git a/ert/bin/scripts/fm_lgr.py b/ert/bin/scripts/fm_lgr.py index e91dc48..6896c9c 100755 --- a/ert/bin/scripts/fm_lgr.py +++ b/ert/bin/scripts/fm_lgr.py @@ -21,7 +21,7 @@ parser.add_argument("file_grid", help="LGR grid file") parser.add_argument("file_sch", help="LGR schedule file") parser.add_argument("size", help="LGR size") -parser.add_argument("file_dual", help="File with dual porosoty option") +parser.add_argument("file_dual", help="File with dual porosity option") def create_wellspec_dataframe(f): @@ -33,14 +33,14 @@ def create_wellspec_dataframe(f): for line in f: if line.strip(): # Remove empty lines words = line.split() - if flag2 is True: + if flag2: if words[0] == "/": flag2 = False else: words = words[:-1] # Remove last item in list, / df_welspecs.loc[i] = words i += 1 - if flag1 is True: + if flag1: df_welspecs = pd.DataFrame(columns=words) flag1 = False flag2 = True @@ -71,14 +71,14 @@ def create_compdat_dataframe(f): for line in f: if line.strip(): # Remove empty lines words = line.split() - if flag2 is True and not words[0].startswith("-------------------------"): + if flag2 and not words[0].startswith("-------------------------"): if words[0] == "/": flag2 = False else: words = words[:-1] # Remove last item in list, / df_compdat.loc[i] = words i += 1 - if flag1 is True: + if flag1: df_compdat = pd.DataFrame(columns=words) flag1 = False flag2 = True @@ -123,15 +123,15 @@ def test_add_num_lgr(): def remove_same_layer_completions(df_compdat): # Remove completions if same layer for different LGRs - list = [] + drop_indices = [] for i in range(len(df_compdat) - 1): if ( df_compdat["K1"].loc[i] == df_compdat["K1"].loc[i + 1] and df_compdat["LGR"].loc[i] != df_compdat["LGR"].loc[i + 1] ): - list.append(i + 1) - for i in range(len(list)): - df_compdat.drop(list[i], inplace=True) + drop_indices.append(i + 1) + for i in range(len(drop_indices)): + df_compdat.drop(drop_indices[i], inplace=True) df_compdat.reset_index(inplace=True) @@ -139,7 +139,7 @@ def test_remove_same_layer_completions(): df = create_compdat_dataframe( ["COMPDAT", "--WELL I J K1", "name1 2 3 4 /", "name2 4 5 4 /", "/"] ) - lgr = add_num_lgr(df) + add_num_lgr(df) remove_same_layer_completions(df) assert df.to_csv() == ",index,--WELL,I,J,K1,LGR\n0,0,name1,2,3,4,1\n" @@ -245,12 +245,13 @@ def write_lgr_config_file(lgr, df_compdat, f, ncells, size, dual): f.write("HXFIN\n") if size == "small": f.write( - " 2*1 4*1 0.21 0.16 0.08 0.04 0.02 0.04 0.08 0.16 0.21 4*1 2*1 /\n" + " 2*1 4*1 0.21 0.16 0.08 0.04 0.02 0.04" + " 0.08 0.16 0.21 4*1 2*1 /\n" ) elif size == "large": f.write( " 2*1 4*1 4*1 4*1 4*1 8*1 8*1 0.21 0.16" - " 0.08 0.04 0.02 0.04 0.08 0.16 0.21 8*1 8*1 4*1 4*1 4*1 4*1 2*1 /\n" + " 0.08 0.04 0.02 0.04 0.08 0.16 0.21 8*1 8*1 4*1 4*1 4*1 4*1 2*1 /\n" ) f.write("\n") f.write("NYFIN\n") @@ -262,12 +263,13 @@ def write_lgr_config_file(lgr, df_compdat, f, ncells, size, dual): f.write("HYFIN\n") if size == "small": f.write( - " 2*1 4*1 0.21 0.16 0.08 0.04 0.02 0.04 0.08 0.16 0.21 4*1 2*1 /\n" + " 2*1 4*1 0.21 0.16 0.08 0.04 0.02 0.04" + " 0.08 0.16 0.21 4*1 2*1 /\n" ) elif size == "large": f.write( " 2*1 4*1 4*1 4*1 4*1 8*1 8*1 0.21 0.16" - " 0.08 0.04 0.02 0.04 0.08 0.16 0.21 8*1 8*1 4*1 4*1 4*1 4*1 2*1 /\n" + " 0.08 0.04 0.02 0.04 0.08 0.16 0.21 8*1 8*1 4*1 4*1 4*1 4*1 2*1 /\n" ) f.write("\n") f.write("ENDFIN\n") @@ -291,7 +293,7 @@ def test_write_lgr_config_file(): buffer, 1, "small", - False, + 0, ) assert ( buffer.getvalue() @@ -320,11 +322,13 @@ def test_write_lgr_config_file(): def write_welspecl(df_welspecs, df_compdat, index, f): f.write("WELSPECL\n") f.write( - df_welspecs.columns.values[0] + " " + df_welspecs.columns.values[1] + " LGR " + df_welspecs.columns.values[0] + + " " + + df_welspecs.columns.values[1] + + " LGR " + + " ".join(df_welspecs.columns.values[2:]) + + "\n" ) - for i in range(2, len(df_welspecs.columns.values)): - f.write(df_welspecs.columns.values[i] + " ") - f.write("\n") for i in range(len(df_welspecs)): f.write( df_welspecs["--WELL"].loc[i] @@ -366,7 +370,7 @@ def test_write_welspecl(): assert ( buffer.getvalue() == """WELSPECL ---WELL GROUP LGR DREF PHASE +--WELL GROUP LGR DREF PHASE well group LGR3 50 50 dref phase / / @@ -376,10 +380,12 @@ def test_write_welspecl(): def write_compdatl(df_compdat, dual, index, f): f.write("COMPDATL\n") - f.write(df_compdat.columns.values[1] + " LGR ") - for i in range(2, len(df_compdat.columns.values) - 1): - f.write(df_compdat.columns.values[i] + " ") - f.write("\n") + f.write( + df_compdat.columns.values[1] + + " LGR " + + " ".join(df_compdat.columns.values[2:-1]) + + "\n" + ) for i in range(len(df_compdat)): k = df_compdat["K1"][ df_compdat["LGR"] == df_compdat["LGR"].loc[i] @@ -460,14 +466,14 @@ def test_write_compdatl(): "DIR": ["dir"], } ), - False, + 0, 50, buffer, ) assert ( buffer.getvalue() == """COMPDATL ---WELL LGR LGR K1 K2 OP/SH WBDIA SKIN +--WELL LGR LGR K1 K2 OP/SH WBDIA SKIN well LGRname 50 50 1 2 1.0 2* wbdia 1* skin 1* dir / / """ @@ -486,19 +492,16 @@ def run(file_well, file_eclipse, file_runspec, file_grid, file_sch, size, file_d # Dual porosity modelling option # 0 = SP, 1 = DP, 2 = DPDK - f = open(file_dual) - dual = int(f.read(1)) - f.close() + with open(file_dual) as f: + dual = int(f.read(1)) # ------------------------------------------------- - f = open(file_well) - df_welspecs = create_wellspec_dataframe(f) - f.close() + with open(file_well) as f: + df_welspecs = create_wellspec_dataframe(f) - f = open(file_well) - df_compdat = create_compdat_dataframe(f) - f.close() + with open(file_well) as f: + df_compdat = create_compdat_dataframe(f) lgr = add_num_lgr(df_compdat) remove_same_layer_completions(df_compdat) @@ -506,75 +509,67 @@ def run(file_well, file_eclipse, file_runspec, file_grid, file_sch, size, file_d # ------------------------------------------------- - f = open(file_runspec, "w") - write_lgr_runspec_file(df_compdat, f) - f.close() + with open(file_runspec, "w") as f: + write_lgr_runspec_file(df_compdat, f) # LGR grid file - f = open(file_grid, "w") - write_lgr_config_file(lgr, df_compdat, f, ncells, size, dual) - f.close() - # LGR schedule file - f = open(file_sch, "w") - - f2 = open(file_well) + with open(file_grid, "w") as f: + write_lgr_config_file(lgr, df_compdat, f, ncells, size, dual) - flag = False - for line in f2: - if line.strip(): # Remove empty lines - words = line.split() - if flag is True: - if words[0] == "/": - f.write(line) - flag = False - else: + # LGR schedule file + with open(file_sch, "w") as f, open(file_well) as f2: + flag = False + for line in f2: + if line.strip(): + words = line.split() + if flag: + if words[0] == "/": + f.write(line) + flag = False + else: + f.write(line) + if words[0] == "GRUPTREE": f.write(line) - if words[0] == "GRUPTREE": - f.write(line) - flag = True - f.write("\n") - - f2.close() - - write_welspecl(df_welspecs, df_compdat, index, f) - write_compdatl(df_compdat, dual, index, f) - f.close() + flag = True + f.write("\n") + write_welspecl(df_welspecs, df_compdat, index, f) + write_compdatl(df_compdat, dual, index, f) # ------------------------------------------------- # Update Eclipse .DATA file - f = open(file_eclipse) - f2 = open(file_eclipse + ".tmp", "w") - for line in f: - if line.startswith("GRID") and not line.startswith("GRIDFILE"): - f2.write("INCLUDE\n") - f2.write(" '../include/runspec/" + file_runspec.split("/")[-1] + "' /\n") - f2.write("\n") - if line.startswith("EDIT"): - f2.write("INCLUDE\n") - f2.write(" '../include/grid/" + file_grid.split("/")[-1] + "' /\n") - f2.write("\n") - if ".sch" in line: - sch = line.split()[0].split("/")[-1].replace("'", "") - f2.write(line) - f2.close() - f.close() + sch = None + with open(file_eclipse) as f, open(file_eclipse + ".tmp", "w") as f2: + for line in f: + if line.startswith("GRID") and not line.startswith("GRIDFILE"): + f2.write("INCLUDE\n") + f2.write( + " '../include/runspec/" + file_runspec.split("/")[-1] + "' /\n" + ) + f2.write("\n") + if line.startswith("EDIT"): + f2.write("INCLUDE\n") + f2.write(" '../include/grid/" + file_grid.split("/")[-1] + "' /\n") + f2.write("\n") + if ".sch" in line: + sch = line.split()[0].split("/")[-1].replace("'", "") + f2.write(line) os.rename(file_eclipse + ".tmp", file_eclipse) # Update Eclipse schedule file sch2 = file_sch.split("/") - dir = file_sch.rsplit("/", 1)[0] - f = open(dir + "/" + sch) - f2 = open(dir + "/" + sch + ".tmp", "w") - for line in f: - if "schedule" in line: - sch3 = line.split()[0].split("/")[-1].replace("'", "") - line = line.replace(sch3, sch2[-1]) - f2.write(line) - f2.close() - f.close() - os.rename(dir + "/" + sch + ".tmp", dir + "/" + sch) + directory = file_sch.rsplit("/", 1)[0] + with ( + open(directory + "/" + sch) as f, + open(directory + "/" + sch + ".tmp", "w") as f2, + ): + for line in f: + if "schedule" in line: + sch3 = line.split()[0].split("/")[-1].replace("'", "") + line = line.replace(sch3, sch2[-1]) + f2.write(line) + os.rename(directory + "/" + sch + ".tmp", directory + "/" + sch) if __name__ == "__main__": diff --git a/ert/bin/scripts/fm_xsect_wells.py b/ert/bin/scripts/fm_xsect_wells.py index b777f2d..8a8840f 100755 --- a/ert/bin/scripts/fm_xsect_wells.py +++ b/ert/bin/scripts/fm_xsect_wells.py @@ -6,16 +6,16 @@ # alifb June 2024 import argparse +import os import pathlib import re -import os -import xtgeo +import xtgeo import xtgeoviz.plot as plot -DESCRIPTION = """ -Create a png file with cross section of well path and surfaces and optional grid properties -Input argument is RUNPATH. +DESCRIPTION = """ Create a png file with cross section of well path and surfaces and +optional grid properties. Input argument is RUNPATH. + Hardcoded: Location (relative to RUNPATH) and name of data (surfaces, wells and polygons). Data must be located in share/results/ wells, maps and polygons folders. @@ -46,7 +46,8 @@ GRID = "share/results/grids/eclgrid.roff" -# Tuple of property name, file path (ROFF file) and plot range (ignore to use auto range) +# Tuple of property name, file path (ROFF file) and plot range +# (ignore to use auto range) GRID_PROPS = [ ("SOIL_20200701", "share/results/grids/eclgrid--soil--20200701.roff", [0, 1]), ("SGAS_20200701", "share/results/grids/eclgrid--sgas--20200701.roff", [0, 1]), diff --git a/sim2seis/bin/run_multi_pem.py b/sim2seis/bin/run_multi_pem.py index b6db6c5..beccfad 100755 --- a/sim2seis/bin/run_multi_pem.py +++ b/sim2seis/bin/run_multi_pem.py @@ -10,14 +10,12 @@ import time from os import getenv, remove -import pandas as pd +import fmu.config.utilities as utils import open_petro_elastic as pem +import pandas as pd from open_petro_elastic.__main__ import ( make_input, - load_data_from_csv, ) -import fmu.config.utilities as utils - # Read environment variable SIM2SEIS_PRED = getenv("FLOWSIM_IS_PREDICTION")