Skip to content

Commit

Permalink
Fixes for ResInsight 2021.06 release (#395)
Browse files Browse the repository at this point in the history
* Ensuring rips deep reload for development version

* Fixes for 2021.06 release - input case file names, wrapper script template and workaround for dev version

* Fixing units in ResInsight test project to silence some warnings..

* Blacking..

* Detecting ResInsight major version < rips major version

* Fixed version triplet type

* Extracting version string using python, moved parsing to separate function).

* Simplifying launching (more robust vs different versions) and updating tests accordingly

* Ensuring rips deep reload for development version

* Fixes for 2021.06 release - input case file names, wrapper script template and workaround for dev version

* Fixing units in ResInsight test project to silence some warnings..

* Blacking..

* Detecting ResInsight major version < rips major version

* Fixed version triplet type

* Extracting version string using python, moved parsing to separate function).

* Simplifying launching (more robust vs different versions) and updating tests accordingly

* Fixing line length > 88

* Rebased (?) and manually added #PR396

* Moving rips intsall after pip upgrade

* Trying to fix rips pip-install return value

* Fixing some type hints
  • Loading branch information
vkip authored and berland committed Jun 18, 2021
1 parent 6458685 commit a92f349
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 95 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/subscript.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
black --check *.py src tests
pip install flake8
flake8 src tests
- name: Install OPM-flow and ResInsight (for testing)
run: |
sudo apt-get install software-properties-common
Expand All @@ -60,6 +60,11 @@ jobs:
pip install --upgrade pip
pip install .[tests,docs]
- name: Force correct RIPS version
run: |
ResInsight --console --help | grep "ResInsight v. 2021.06" && pip install rips==2021.6.0.1 || true
ResInsight --console --help | grep "ResInsight v. 2020.10" && pip install rips==2020.10.0.2 || true
- name: Enforce static typing
run: |
pip install mypy
Expand Down
163 changes: 83 additions & 80 deletions src/subscript/ri_wellmod/ri_wellmod.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
from pathlib import Path
import os
import subprocess
import tempfile
import fnmatch
import shutil
Expand Down Expand Up @@ -69,11 +70,11 @@
logger = getLogger(__name__)

RI_HOME = "/prog/ResInsight"
WRAPPER_TEMPLATE = """
#!/bin/bash
WRAPPER_TEMPLATE = """#!/bin/bash
unset LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/prog/ResInsight/6.14-3_odb_api/lib
"""
RI_VERSION_REX = re.compile(r".*(\d{4}\.\d{2}\.\d+).*", re.DOTALL)


class CustomFormatter(
Expand All @@ -90,31 +91,72 @@ class CustomFormatter(

def get_resinsight_exe() -> Optional[str]:
"""
Return the path to a ResInsight executable (or wrapper script), None if not found.
Return the path to a ResInsight executable (or wrapper script).
Returns None if not found or major version < rips major version.
"""
ri_exe = shutil.which("ResInsight")
if ri_exe is not None:
return ri_exe
if not ri_exe:
ri_exe = shutil.which("resinsight")

ri_exe = shutil.which("resinsight")
if ri_exe is not None:
return ri_exe
if not ri_exe:
return None

ri_triplet = get_resinsight_version_triplet(ri_exe)
rips_triplet = get_rips_version_triplet()
if ri_triplet[0] != rips_triplet[0]:
logger.debug(
"ResInsight version in path does not match rips version (%d)",
rips_triplet[0],
)
return None

return ri_exe


def get_resinsight_version_string(ri_exe: str) -> str:
"""
Find version string from ResInsight help output
"""
output_bytes = subprocess.check_output([ri_exe, "--console", "--help"])
output_string = output_bytes.decode("UTF-8")
match = RI_VERSION_REX.match(output_string)
if not match:
return ""

return match.group(1)


def get_resinsight_version_triplet(ri_exe: str) -> Tuple[int, int, int]:
"""
Get the rips (client-side) version, without instanciating/launching ResInsight
"""
version_string = get_resinsight_version_string(ri_exe)
version_string_triplet = version_string.strip().split(sep=".")
major = minor = patch = 0
if len(version_string_triplet) == 3:
try:
major, minor, patch = [int(num) for num in version_string_triplet]
except ValueError:
logger.debug(
"Unable to extract version triplet from string %s, returning (0,0,0)",
version_string,
)

return None
return (major, minor, patch)


def get_rips_version_triplet() -> Tuple[int, int, str]:
def get_rips_version_triplet() -> Tuple[int, int, int]:
"""
Get the rips (client-side) version, without instanciating/launching ResInsight
"""
major = rips.instance.RiaVersionInfo.RESINSIGHT_MAJOR_VERSION
minor = rips.instance.RiaVersionInfo.RESINSIGHT_MINOR_VERSION
patch = rips.instance.RiaVersionInfo.RESINSIGHT_PATCH_VERSION
major = int(rips.instance.RiaVersionInfo.RESINSIGHT_MAJOR_VERSION)
minor = int(rips.instance.RiaVersionInfo.RESINSIGHT_MINOR_VERSION)
patch = int(rips.instance.RiaVersionInfo.RESINSIGHT_PATCH_VERSION)
return (major, minor, patch)


def find_and_wrap_resinsight_version(
version_triplet: Tuple[int, int, str]
version_triplet: Tuple[int, int, int]
) -> Optional[str]:
"""
Find a ResInsight executable matching at least the major.minor version
Expand Down Expand Up @@ -157,7 +199,7 @@ def _find_ri_exe(pattern: str) -> Optional[Path]:
wrapper_file = tempfile.NamedTemporaryFile(delete=False)
with open(wrapper_file.name, "w") as fhandle:
print(WRAPPER_TEMPLATE, file=fhandle)
print(f'{resinsight_exe} "$@"', file=fhandle)
print(f'exec {resinsight_exe} "$@"', file=fhandle)
fhandle.flush()
os.chmod(wrapper_file.name, 0o770)
wrapper_file.close()
Expand Down Expand Up @@ -185,6 +227,11 @@ def launch_resinsight(console_mode: bool, command_line_parameters: List[str]):
rips_version_triplet = get_rips_version_triplet()
resinsight_exe = find_and_wrap_resinsight_version(rips_version_triplet)
if not resinsight_exe:
logger.critical(
"Unable to find the %d version of ResInsight (to match \
the rips version)",
rips_version_triplet[0],
)
return False
wrapper = True

Expand All @@ -196,74 +243,24 @@ def launch_resinsight(console_mode: bool, command_line_parameters: List[str]):
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
if (
len(any_exception.args) > 3
and any_exception.args[0].find("Wrong Version") >= 0
):
server_version_triplet = any_exception.args[2].split(".")
smajor, sminor, spatch = server_version_triplet
logger.error(
"Wrong ResInsight version - found (%s.%s.%s), requires (%s.%s.*)",
smajor,
sminor,
spatch,
cmajor,
cminor,
logger.error(str(any_exception))
logger.debug(
"Failed to launch ResInsight (%s)- trying once more", resinsight_exe
)
try: # Second launch attempt
resinsight = rips.Instance.launch(
resinsight_executable=resinsight_exe,
console=console_mode,
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
logger.error(str(any_exception))
logger.critical(
"Failed to launch ResInsight (%s) again - stopping now.", resinsight_exe
)
if (
wrapper
): # If already tried via wrapper, no need to search, just try again
logger.debug(
"Trying to launch ResInsight wrapper again: %s", resinsight_exe
)
try: # Second launch attempt via wrapper
resinsight = rips.Instance.launch(
resinsight_executable=resinsight_exe,
console=console_mode,
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
Path(resinsight_exe).unlink() # Delete wrapper
logger.error(str(any_exception))
return False
else: # Not via wrapper - try to find a valid install and wrap it
resinsight_exe = find_and_wrap_resinsight_version(
get_rips_version_triplet()
)
if not resinsight_exe:
return False
wrapper = True
try: # First launch attempt via wrapper
resinsight = rips.Instance.launch(
resinsight_executable=resinsight_exe,
console=console_mode,
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
logger.error(str(any_exception))
try: # Second launch attempt via wrapper
resinsight = rips.Instance.launch(
resinsight_executable=resinsight_exe,
console=console_mode,
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
Path(resinsight_exe).unlink()
logger.error(str(any_exception))
return False
else: # Not a version error, just try a second time
try:
resinsight = rips.Instance.launch(
resinsight_executable=resinsight_exe,
console=console_mode,
command_line_parameters=command_line_parameters,
)
except Exception as any_exception: # pylint: disable=broad-except
logger.error(str(any_exception))
return False

if wrapper:
Path(resinsight_exe).unlink()
Path(resinsight_exe).unlink() # Delete wrapper

return resinsight

Expand Down Expand Up @@ -339,6 +336,7 @@ def launch_resinsight_dev(
sys.path.insert(0, str(ridir))
sys.path.insert(0, str(pypath))
deep_reload(rips, pypath)
reload(rips.case)
sys.path.pop(0)
try:
resinsight = rips.Instance.launch(
Expand Down Expand Up @@ -766,10 +764,15 @@ def get_lgr_spec_filename(lgr_well_path: str) -> Path:
lgr_spec_fn = lgr_spec_fn.replace(" ", "_")
return Path(tmp_output_folder) / lgr_spec_fn

orig_ri_case_name = ri_case_name
ri_case_name = ri_case_name.replace(".", "_")
with open(output_file, "w") as out_fd:
for well in well_path_names:
perf_fn = get_exported_perf_filename(well, ri_case_name)
# Check for case name with '.' due to behavioural change in 2021.06 release
orig_perf_fn = get_exported_perf_filename(well, orig_ri_case_name)
if orig_perf_fn.exists() and not perf_fn.exists():
perf_fn = orig_perf_fn

# Need to check if LGR perfs exists, in case of non-LGR wells intersecting
# well LGRs, or in case of LGRs present in the init case
Expand Down
33 changes: 25 additions & 8 deletions tests/test_ri_wellmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ def has_display():
return "DISPLAY" in os.environ and os.environ["DISPLAY"]


def has_resinsight():
"""
Check for a valid ResInsight install
"""
if ri_wellmod.get_resinsight_exe():
return True

wrapper = ri_wellmod.find_and_wrap_resinsight_version(
ri_wellmod.get_rips_version_triplet()
)
if wrapper:
Path(wrapper).unlink()
return True

return False


def file_contains(filename, string_to_find):
"""
Utility function to check if a file contains a given string.
Expand All @@ -56,7 +73,7 @@ def test_integration():


@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(drogon_runpath() is None, reason="Could not find Drogon data")
def test_main_initcase(tmpdir, mocker):
Expand All @@ -73,7 +90,7 @@ def test_main_initcase(tmpdir, mocker):


@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(),
not has_resinsight(),
reason="Could not find a ResInsight executable",
)
def test_main_inputcase(tmpdir, mocker):
Expand Down Expand Up @@ -104,7 +121,7 @@ def test_main_inputcase(tmpdir, mocker):


@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(drogon_runpath() is None, reason="Could not find Drogon data")
def test_drogon_mswdef(tmpdir, mocker):
Expand All @@ -125,7 +142,7 @@ def test_drogon_mswdef(tmpdir, mocker):


@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(drogon_runpath() is None, reason="Could not find Drogon data")
def test_drogon_lgr(tmpdir, mocker):
Expand All @@ -146,7 +163,7 @@ def test_drogon_lgr(tmpdir, mocker):


@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(drogon_runpath() is None, reason="Could not find Drogon data")
@pytest.mark.skipif(not has_display(), reason="Requires X display")
Expand Down Expand Up @@ -183,7 +200,7 @@ def test_main_lgr_cmdline(tmpdir, mocker):

@pytest.mark.integration
@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(drogon_runpath() is None, reason="Could not find Drogon data")
@pytest.mark.skipif(not HAVE_ERT, reason="Requires ERT")
Expand Down Expand Up @@ -223,7 +240,7 @@ def test_ert_forward_model(tmpdir):

# REEK TESTS
@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
def test_main_initcase_reek(tmpdir, mocker):
"""Test well data generation from init case on Reek"""
Expand All @@ -240,7 +257,7 @@ def test_main_initcase_reek(tmpdir, mocker):

# This one requires a GUI (for now)
@pytest.mark.skipif(
not ri_wellmod.get_resinsight_exe(), reason="Could not find a ResInsight executable"
not has_resinsight(), reason="Could not find a ResInsight executable"
)
@pytest.mark.skipif(not has_display(), reason="Requires X display")
def test_main_lgr_reek(tmpdir, mocker):
Expand Down
Loading

0 comments on commit a92f349

Please sign in to comment.