Skip to content

Commit

Permalink
Write guidefiles
Browse files Browse the repository at this point in the history
  • Loading branch information
verveerpj committed Jul 6, 2024
1 parent bcf0c34 commit 054f0fe
Show file tree
Hide file tree
Showing 19 changed files with 3,771 additions and 3,262 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
- id: end-of-file-fixer
exclude: tests/testdata
- id: trailing-whitespace
exclude: tests/testdata/well_trajectory/spe1case1/expected
exclude: tests/testdata/well_trajectory/.*/expected
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.1.2
hooks:
Expand Down
9 changes: 7 additions & 2 deletions src/everest_models/jobs/fm_well_trajectory/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from pathlib import Path

from .outputs import write_guide_points
from .outputs import write_guide_points, write_mlt_guide_md, write_mlt_guide_points
from .parser import build_argument_parser
from .read_trajectories import read_trajectories
from .well_trajectory_resinsight import well_trajectory_resinsight
Expand Down Expand Up @@ -41,11 +41,16 @@ def main_entry_point(args=None):
eclipse_model := options.eclipse_model or options.config.eclipse_model
) is None:
args_parser.error("missing eclipse model")
well_trajectory_resinsight(
mlt_guide_points = well_trajectory_resinsight(
options.config,
eclipse_model,
guide_points,
)
if mlt_guide_points:
logger.info("Writing multilateral guide points to 'mlt_guide_points.json'")
write_mlt_guide_points(mlt_guide_points, Path("mlt_guide_points.json"))
logger.info("Writing multilateral guide md's to 'mlt_guide_md.json'")
write_mlt_guide_md(mlt_guide_points, Path("mlt_guide_md.json"))


if __name__ == "__main__":
Expand Down
44 changes: 26 additions & 18 deletions src/everest_models/jobs/fm_well_trajectory/outputs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import csv
import math
from pathlib import Path
from typing import Dict, Iterable, Tuple
Expand Down Expand Up @@ -69,32 +68,41 @@ def f180(a: float) -> float:
)


def _csv_writer(path: Path, guide_points: Dict[str, Trajectory]):
with path.open("w", encoding="utf-8") as csv_file:
writer = csv.writer(csv_file, delimiter=";", lineterminator="\n")
writer.writerow(["well", "x", "y", "z"])
writer.writerows(
[well, x, y, z]
def write_guide_points(guide_points: Dict[str, Trajectory], filename: Path) -> None:
io.dump_json(
{
well: [data.x.tolist(), data.y.tolist(), data.z.tolist()]
for well, data in guide_points.items()
for x, y, z in zip(data.x, data.y, data.z)
)
},
filename,
)


def _json_writer(path: Path, guide_points: Dict[str, Trajectory]):
def write_mlt_guide_points(guide_points: Dict[str, Trajectory], filename: Path) -> None:
io.dump_json(
{
well: [data.x.tolist(), data.y.tolist(), data.z.tolist()]
for well, data in guide_points.items()
well: {
branch: [
branch_data[1].x.tolist(),
branch_data[1].y.tolist(),
branch_data[1].z.tolist(),
]
for branch, branch_data in well_data.items()
}
for well, well_data in guide_points.items()
},
path,
filename,
)


def write_guide_points(guide_points: Dict[str, Trajectory], filename: Path) -> None:
if writer := {".csv": _csv_writer, ".json": _json_writer}.get(filename.suffix):
writer(filename, guide_points)
else:
raise RuntimeError("guide points file format not supported")
def write_mlt_guide_md(guide_points: Dict[str, Trajectory], filename: Path) -> None:
io.dump_json(
{
well: {branch: branch_data[0] for branch, branch_data in well_data.items()}
for well, well_data in guide_points.items()
},
filename,
)


def write_well_costs(costs: Dict[str, float], npv_file: Path) -> None:
Expand Down
43 changes: 13 additions & 30 deletions src/everest_models/jobs/fm_well_trajectory/resinsight.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def read_wells(
well_path_folder: Path,
well_names: Iterable[str],
connection: Optional[ResInsightConnectionConfig],
) -> rips.Project:
) -> None:
project.import_well_paths(
well_path_files=[
str(well_path_folder / f"{well_name}.dev") for well_name in well_names
Expand All @@ -56,42 +56,38 @@ def read_wells(

project.update()

return project


def create_well(
connection: ResInsightConnectionConfig,
measured_depth_step: float,
well: WellConfig,
trajectory: Trajectory,
well_config: WellConfig,
guide_points: Trajectory,
project: rips.Project,
project_path: Path,
) -> rips.Project:
) -> None:
_create_perforation_view(
connection.perforations,
connection.formations_file,
project.cases()[0],
well.name,
well_config.name,
)

well_path_collection = project.descendants(rips.WellPathCollection)[0]
well_path = well_path_collection.add_new_object(rips.ModeledWellPath)
well_path.name = well.name
well_path.name = well_config.name
well_path.update()

geometry = well_path.well_path_geometry()
reference_point = geometry.reference_point
reference_point[0] = str(trajectory.x[0])
reference_point[1] = str(trajectory.y[0])
reference_point[2] = str(trajectory.z[0])
reference_point[0] = str(guide_points.x[0])
reference_point[1] = str(guide_points.y[0])
reference_point[2] = str(guide_points.z[0])
geometry.update()

intersection_points = []
for point in zip(trajectory.x[1:], trajectory.y[1:], trajectory.z[1:]):
for point in zip(guide_points.x[1:], guide_points.y[1:], guide_points.z[1:]):
coord = [str(item) for item in point]
target = geometry.append_well_target(coordinate=coord, absolute=True)
target.dogleg1 = well.dogleg
target.dogleg2 = well.dogleg
target.dogleg1 = well_config.dogleg
target.dogleg2 = well_config.dogleg
target.update()
intersection_points.append(coord)
geometry.update()
Expand All @@ -113,17 +109,6 @@ def create_well(
)
)

project_file = project_path / "model.rsp"
logger.info(f"Saving project to: {project_file}")
project.save(str(project_file))

logger.info(
f"Calling 'export_well_paths' on the resinsight project" f"\ncwd = {Path.cwd()}"
)
project.export_well_paths(well_paths=None, md_step_size=measured_depth_step)

return project


def _find_time_step(
case: rips.Case, date: Optional[datetime.date] = None
Expand Down Expand Up @@ -160,7 +145,7 @@ def create_well_logs(
eclipse_model: Path,
project_path: Path,
date: Optional[datetime.date] = None,
) -> rips.Project:
) -> None:
case = project.cases()[0]

well_log_plot_collection = project.descendants(rips.WellLogPlotCollection)[0]
Expand Down Expand Up @@ -212,8 +197,6 @@ def create_well_logs(

project.update()

return project


def _filter_properties(
conditions: pandas.Series,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import logging
import signal
import sys
from contextlib import contextmanager
from pathlib import Path
from typing import Dict, Optional

import rips

from .models.config import ConfigSchema, ResInsightInterpolationConfig
from .outputs import write_well_costs
from .read_trajectories import read_laterals
from .resinsight import create_well, create_well_logs, make_perforations, read_wells
from .well_costs import compute_well_costs
from .well_trajectory_simple import Trajectory
Expand Down Expand Up @@ -41,73 +41,94 @@ def __exit__(self, *_) -> None:
self._instance.exit()


@contextmanager
def resinsight_project(project: rips.Project, egrid_path: str, project_file: str):
project.load_case(egrid_path)
yield project
def _save_project(project_path: str, project: rips.Project):
project_file = str(project_path / "model.rsp")
logger.info(f"Saving project to: {project_file}")
project.save(project_file)


def _save_paths(project_path: str, project: rips.Project, mds: float):
_save_project(project_path, project)
logger.info(
f"Calling 'export_well_paths' on the resinsight project" f"\ncwd = {Path.cwd()}"
)
project.export_well_paths(well_paths=None, md_step_size=mds)


def well_trajectory_resinsight(
config: ConfigSchema,
eclipse_model: Path,
guide_points: Dict[str, Trajectory],
project_path: Optional[Path] = None,
) -> None:
mlt_guide_points = {}
if project_path is None:
project_path = Path.cwd()
with ResInsight(
"" if config.resinsight_binary is None else str(config.resinsight_binary)
) as resinsight:
with resinsight_project(
resinsight.project,
str(eclipse_model.with_suffix(".EGRID")),
str(project_path / "model.rsp"),
) as project:
if isinstance(config.interpolation, ResInsightInterpolationConfig):
# Interpolate trajectories and save smooth trajectories:
for well in config.wells:
project = create_well(
config.connections,
config.interpolation.measured_depth_step,
well,
guide_points[well.name],
project,
project_path,
)
else:
# Simple interpolation, use saved trajectories:
project = read_wells(
project,
project_path / "wellpaths",
[well.name for well in config.wells],
resinsight.project.load_case(str(eclipse_model.with_suffix(".EGRID")))

if isinstance(config.interpolation, ResInsightInterpolationConfig):
# Interpolate trajectories and save smooth trajectories:
for well_config in config.wells:
create_well(
config.connections,
well_config,
guide_points[well_config.name],
resinsight.project,
)
project = create_well_logs(
config.connections.perforations,
project,
eclipse_model,
_save_paths(
project_path,
config.connections.date,
resinsight.project,
config.interpolation.measured_depth_step,
)
wells = itertools.filterfalse(
lambda x: x is None,
(
make_perforations(
project,
well_path.name,
config.connections.perforations,
config.wells,
project_path,
)
for well_path in project.well_paths()
),

mlt_guide_points = read_laterals(
config.scales, config.references, config.wells
)
if config.npv_input_file is not None:
write_well_costs(
costs=compute_well_costs(wells),
npv_file=config.npv_input_file,
if mlt_guide_points:
_save_paths(
project_path,
resinsight.project,
config.interpolation.measured_depth_step,
)
else:
all(wells) # consume generator without collecting yields
else:
# Simple interpolation, use saved trajectories:
read_wells(
resinsight.project,
project_path / "wellpaths",
[well.name for well in config.wells],
config.connections,
)
create_well_logs(
config.connections.perforations,
resinsight.project,
eclipse_model,
project_path,
config.connections.date,
)
wells = itertools.filterfalse(
lambda x: x is None,
(
make_perforations(
resinsight.project,
well_path.name,
config.connections.perforations,
config.wells,
project_path,
)
for well_path in resinsight.project.well_paths()
),
)
if config.npv_input_file is not None:
write_well_costs(
costs=compute_well_costs(wells),
npv_file=config.npv_input_file,
)
else:
all(wells) # consume generator without collecting yields

_save_project(project_path, resinsight.project)

return mlt_guide_points
14 changes: 14 additions & 0 deletions tests/jobs/well_trajectory/test_well_trajectory_resinsight.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,17 @@ def test_well_trajectory_resinsight_main_entry_point_lint(
assert not any(
path.relative_to("expected").exists() for path in Path("expected").glob("**/*")
)


@pytest.mark.resinsight
def test_well_trajectory_resinsight_main_entry_point_mlt(
well_trajectory_arguments, copy_testdata_tmpdir
):
copy_testdata_tmpdir(Path(TEST_DATA) / "spe1case1_mlt")
main_entry_point(well_trajectory_arguments)

for expected in Path("expected").glob("**/*"):
if expected.is_file():
output = expected.relative_to("expected")
assert output.is_file()
assert filecmp.cmp(expected, output, shallow=False)
2 changes: 1 addition & 1 deletion tests/testdata/well_trajectory/spe1case1/expected/PROD.SCH
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ WELSPECS
-- WELL OPEN SAT CONN WELL KH SKIN D DIR
-- NAME I J K1 K2 SHUT TAB FACT DIA FACT FACT FACT PEN
COMPDAT
PROD 8 8 3 3 OPEN 1* 7.456372E+01 0.30000 9.999965E+03 0.00000 1* 'Z' /
PROD 8 8 3 3 OPEN 1* 7.456394E+01 0.30000 9.999995E+03 0.00000 1* 'Z' /
/
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
0.0,
50.0,
8325.0,
8400.0,
8375.0,
8425.0
]
]
Expand Down
Loading

0 comments on commit 054f0fe

Please sign in to comment.