Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fixing an issue where an incorrect well type will sometimes be assigned when loading in wells. #450

Merged
merged 1 commit into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ResSimpy/Nexus/NexusWells.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ def _load(self) -> None:
self._wells = wells
self.__date_format = date_format
self._wells_loaded = True
# Ensure the newly added wells have additional information populated from the surface file.
self.model.network.get_load_status()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this always mean that network will be loaded after the wells are loaded?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.


def modify(self, well_name: str, completion_properties_list: list[dict[str, None | float | int | str]],
how: OperationEnum = OperationEnum.ADD) -> None:
Expand Down
7 changes: 7 additions & 0 deletions tests/Nexus/nexus_simulator/test_nexus_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ def test_get_all(mocker: MockerFixture, fcs_file_contents: str):
['\n', ' WelLS sEt 1 my/wellspec/file.dat\n', ' '])

simulation = NexusSimulator(origin='path/nexus_run.fcs')
simulation.model_files.surface_files = {}

# Act
result = simulation.wells.get_all()
Expand Down Expand Up @@ -1142,6 +1143,7 @@ def test_get_wells_windows(mocker: MockerFixture, fcs_file_contents: str):
['\n', ' WelLS sEt 1 my\wellspec\file.dat\n', ' '])

simulation = NexusSimulator(origin='path\nexus_run.fcs')
simulation.model_files.surface_files = {}

# Act
result = simulation.wells.get_all()
Expand Down Expand Up @@ -1185,8 +1187,11 @@ def test_get_df(mocker: MockerFixture):
mock_load_wells = mocker.Mock(return_value=(loaded_wells, ''))
mocker.patch('ResSimpy.Nexus.NexusWells.load_wells', mock_load_wells)
simulation = NexusSimulator(origin='nexus_run.fcs')
simulation.model_files.surface_files = {}

# Act
result = simulation.wells.get_df()

# Assert

pd.testing.assert_frame_equal(result, loaded_wells_df, check_like=True)
Expand Down Expand Up @@ -1227,6 +1232,7 @@ def test_get(mocker: MockerFixture, fcs_file_contents: str):
['\n', ' WelLS set 1 my/wellspec/file.dat\n', ' '])

simulation = NexusSimulator(origin='path/nexus_run.fcs')
simulation.model_files.surface_files = {}

# Act
result = simulation.wells.get(well_name='WELL2')
Expand Down Expand Up @@ -1274,6 +1280,7 @@ def test_get_well_windows(mocker: MockerFixture, fcs_file_contents: str):
['\n', ' WelLS set 1 my\\wellspec\\file.dat\n', ' '])

simulation = NexusSimulator(origin='path\\nexus_run.fcs')
simulation.model_files.surface_files = {}

# Act
result = simulation.wells.get(well_name='WELL2')
Expand Down
81 changes: 79 additions & 2 deletions tests/Nexus/test_load_wells.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test for this. If we don't have the call to the network does this test fail?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It fails for all except the default producer test case, yes.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import pytest
from pytest_mock import MockerFixture

from ResSimpy import NexusSimulator
from ResSimpy.Enums.WellTypeEnum import WellType
from ResSimpy.Nexus.DataModels.NexusCompletion import NexusCompletion
from ResSimpy.Nexus.DataModels.NexusFile import NexusFile
from ResSimpy.Nexus.DataModels.NexusRelPermEndPoint import NexusRelPermEndPoint
Expand Down Expand Up @@ -690,12 +692,15 @@ def test_load_full_model_with_wells(mocker: MockerFixture, first_line_wellspec,
IW JW L RADW
1 2 3 4.5"""

fcs_file_contents = f"{first_line_fcs_file} \n WELLS Set 1 data/wells.dat\n"
surface_contents = ""

fcs_file_contents = f"{first_line_fcs_file} \n WELLS Set 1 data/wells.dat\n SURFACE Network 1 data/surface.dat"

def mock_open_wrapper(filename, mode):
mock_open = mock_multiple_files(mocker, filename, potential_file_dict={
'model.fcs': fcs_file_contents,
'data/wells.dat': wellspec_contents
'data/wells.dat': wellspec_contents,
'data/surface.dat': surface_contents
}).return_value
return mock_open

Expand Down Expand Up @@ -1211,6 +1216,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch("builtins.open", mock_open_wrapper)

nexus_sim = get_fake_nexus_simulator(mocker, fcs_file_path='model.fcs', mock_open=False)
nexus_sim.model_files.surface_files = {}

mocker.patch('ResSimpy.DataModelBaseClasses.DataObjectMixin.uuid4',
side_effect=['uuid_1', 'uuid_2', 'uuid_3', 'uuid_4', 'uuid_5',
Expand Down Expand Up @@ -1369,3 +1375,74 @@ def test_load_wells_wellspec_line_skip_bug(mocker):
assert result_wells[2].completions[0] == expected_completion_3
assert result_wells[3].well_name == 'well4'
assert result_wells[3].completions[0] == expected_completion_4


@pytest.mark.parametrize('stream_text, expected_well_type', [
('WATER', WellType.WATER_INJECTOR),
('PRODUCER', WellType.PRODUCER),
('GAS', WellType.GAS_INJECTOR),
('OIL', WellType.OIL_INJECTOR),
])
def test_load_wells_gives_correct_well_type(mocker: MockerFixture, stream_text: str, expected_well_type: WellType):
input_run_control = "DATEFORMAT DD/MM/YYYY\n START 25/07/2026"
input_nexus_fcs_file = """DATEFORMAT DD/MM/YYYY
RECURRENT_FILES
RUNCONTROL /path/to/run_control.dat
WELLS set 1 /path/to/wells.dat
SURFACE Network 1 /surface_file_01.dat
"""

surface_file_contents = f"""
WELLS
NAME STREAM
well_1 {stream_text}
ENDWELLS

TIME 26/07/2026
ACTIVATE
CONNECTION
well_1
ENDACTIVATE

TIME 27/07/2026
CONSTRAINTS
well_1 QWSMAX 1234
ENDCONSTRAINTS

"""

wellspec_file = """
WELLSPEC well_1
IW JW L RADW
1 2 3 4.5
"""

def mock_open_wrapper(filename, mode):
mock_open = mock_multiple_files(mocker, filename, potential_file_dict={
'/path/to/nexus/fcsfile.fcs': input_nexus_fcs_file,
'/path/to/run_control.dat': input_run_control,
'/path/to/wells.dat': wellspec_file,
'/surface_file_01.dat': surface_file_contents}).return_value
return mock_open

mocker.patch("builtins.open", mock_open_wrapper)

dummy_model = get_fake_nexus_simulator(mocker=mocker, mock_open=False)
dummy_wells = NexusWells(dummy_model)
expected_completion_1 = NexusCompletion(i=1, j=2, k=3, well_radius=4.5, date='25/07/2026',
date_format=DateFormat.DD_MM_YYYY, start_date='25/07/2026')
expected_completions = [expected_completion_1]
expected_well_1 = NexusWell(well_name='well_1', well_type=expected_well_type, completions=expected_completions,
parent_wells_instance=dummy_wells, unit_system=UnitSystem.ENGLISH)
expected_wells = [expected_well_1]

listdir_mock = mocker.Mock(return_value=[])
mocker.patch("os.listdir", listdir_mock)
mocker.patch("os.path.isfile", lambda x: True)

# Act
nexus_model = NexusSimulator(origin='/path/to/nexus/fcsfile.fcs')
result = nexus_model.wells.wells

# Assert
assert result == expected_wells
6 changes: 6 additions & 0 deletions tests/Nexus/test_nexus_well.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch('ResSimpy.DataModelBaseClasses.DataObjectMixin.uuid4', return_value='uuid_1')

nexus_sim = get_fake_nexus_simulator(mocker=mocker, fcs_file_path='fcs_file.fcs', mock_open=False)
nexus_sim.model_files.surface_files = {}

well_1_completions = [
NexusCompletion(date='01/01/2023', i=1, j=2, k=3, skin=None, well_radius=4.5, angle_v=None, grid='GRID1',
Expand Down Expand Up @@ -1025,6 +1026,7 @@ def test_add_completion_write(mocker, file_as_list, add_perf_date,

# add the required attributes to the model class
fake_nexus_sim.model_files.well_files = {1: file}
fake_nexus_sim.model_files.surface_files = {}
fake_nexus_sim.date_format = DateFormat.DD_MM_YYYY
fake_nexus_sim._sim_controls.date_format_string = "%d/%m/%Y"
fake_nexus_sim.start_date = start_date
Expand Down Expand Up @@ -1071,6 +1073,7 @@ def test_add_completion_correct_wellspec(mocker, date_format):

# add the required attributes to the model class
mock_nexus_sim.model_files.well_files = {1: file_1, 2: file_2, 3: file_target}
mock_nexus_sim.model_files.surface_files = {}
mock_nexus_sim.date_format = DateFormat.DD_MM_YYYY
mock_nexus_sim._sim_controls.date_format_string = "%d/%m/%Y"
mock_nexus_sim.start_date = start_date
Expand Down Expand Up @@ -1168,6 +1171,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch("builtins.open", mock_open_wrapper)

mock_nexus_sim = get_fake_nexus_simulator(mocker=mocker, fcs_file_path=fcs_file_path, mock_open=False)
mock_nexus_sim.model_files.surface_files = {}

mock_nexus_sim.start_date = start_date
# mock out open
Expand Down Expand Up @@ -1313,6 +1317,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch("builtins.open", mock_open_wrapper)

model = get_fake_nexus_simulator(mocker=mocker, fcs_file_path='fcs_file.dat', mock_open=False)
model.model_files.surface_files = {}

add_perf_date = '01/02/2020'

Expand Down Expand Up @@ -1405,6 +1410,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch("builtins.open", mock_open_wrapper)

model = get_fake_nexus_simulator(mocker=mocker, fcs_file_path='fcs_file.dat', mock_open=False)
model.model_files.surface_files = {}

add_perf_date = '01/01/2020'

Expand Down
3 changes: 3 additions & 0 deletions tests/Nexus/test_nexus_write_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch('os.path.isfile', fcs_file_exists)

mock_nexus_sim = NexusSimulator('fcs_file.fcs')
mock_nexus_sim.model_files.surface_files = {}
mock_nexus_sim.start_date = start_date
add_perf_dict = {'date': add_perf_date, 'i': 4, 'j': 5, 'k': 6, 'well_radius': 7.5, 'date_format': DateFormat.DD_MM_YYYY}

Expand Down Expand Up @@ -232,6 +233,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch('os.path.isfile', fcs_file_exists)

mock_nexus_sim = NexusSimulator('fcs_file.fcs')
mock_nexus_sim.model_files.surface_files = {}
mock_nexus_sim.start_date = start_date
mock_nexus_sim._wells._load() # Manually call load_wells to simulate loading in wells before we change the open mock.
remove_perf_dict = {'date': remove_perf_date, 'i': 4, 'j': 5, 'k': 6, 'well_radius': 4.2}
Expand Down Expand Up @@ -318,6 +320,7 @@ def mock_open_wrapper(filename, mode):
mocker.patch('os.path.isfile', fcs_file_exists)

mock_nexus_sim = NexusSimulator('fcs_file.fcs')
mock_nexus_sim.model_files.surface_files = {}
mock_nexus_sim.start_date = start_date
modify_perf_target = {'date': modify_perf_date, 'i': 4, 'j': 5, 'k': 6,
'well_radius': 4.2,
Expand Down