Skip to content

Commit

Permalink
Refactor config code to work with doc generator
Browse files Browse the repository at this point in the history
  • Loading branch information
verveerpj committed Jul 12, 2024
1 parent 92b2162 commit b0d6a4c
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 43 deletions.
55 changes: 49 additions & 6 deletions docs/reference/well_trajectory/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# <REPLACE> is a REQUIRED field that needs replacing


# Scaling lengths for the guide points.
# Required: True
scales:

Expand Down Expand Up @@ -30,6 +31,7 @@ scales:
# Default: null
k: null

# Reference points for the guide points.
# Required: True
references:

Expand Down Expand Up @@ -60,15 +62,54 @@ references:

# Options related to interpolation of guide points.
# Required: True
interpolation: <REPLACE>
interpolation:

# Interpolation type: 'simple' or 'resinsight'.
# Datatype: string
# Examples: a string value
# Required: False
# Default: resinsight
type: resinsight

# Simple interpolation only.
# Datatype: integer
# Examples: 1, 1.34E5
# Required: False
# Default: 50
length: 50

# Simple interpolation only.
# Datatype: integer
# Examples: 1, 1.34E5
# Required: False
# Default: 100000
trial_number: 100000

# Simple interpolation only.
# Datatype: number
# Examples: .1, 1., 1, 1.0, 1.34E-5, 1.34e-5
# Required: False
# Default: 0.01
trial_step: 0.01

# ResInsight interpolation only: Step size used in exporting interpolated well trajectories.
# Datatype: integer
# Examples: .1, 1., 1, 1.0, 1.34E-5, 1.34e-5
# Required: False
# Default: 5
measured_depth_step: 5

# Options related to the connections.
# Required: False
# Default: null
connections:

# Datatype: resinsight
# Required: True
type: <REPLACE>
# Connection type: currently only 'resinsight'.
# Datatype: string
# Examples: a string value
# Required: False
# Default: resinsight
type: resinsight

# Simulation date used for grid perforation filtering based on time dynamic grid flow simulation data.
# Datatype: date
Expand Down Expand Up @@ -96,7 +137,7 @@ connections:
dynamic:
-

# Keyword representing a cell property in flow simulator which will be accepted in filtering.
# Keyword representing dynamic cell property in flow simulator which will be accepted in filtering, e.g. PRESSURE.
# Datatype: string
# Examples: a string value
# Required: True
Expand All @@ -118,7 +159,7 @@ connections:
static:
-

# Keyword representing a cell property in flow simulator which will be accepted in filtering.
# Keyword for static (initial) cell property in flow simulator which will be accepted in filtering, e.g. PORO.
# Datatype: string
# Examples: a string value
# Required: True
Expand All @@ -142,6 +183,7 @@ connections:
formations:
- <REPLACE>

# Configuration of the platforms.
# Required: False
platforms:
-
Expand Down Expand Up @@ -171,6 +213,7 @@ platforms:
# Default: null
k: null

# Configuration of the wells.
# Required: True
wells:
-
Expand Down
126 changes: 102 additions & 24 deletions src/everest_models/jobs/fm_well_trajectory/models/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

import datetime
from pathlib import Path
from typing import Literal, Tuple, Union
from typing import Tuple

from pydantic import (
AfterValidator,
Expand All @@ -10,6 +12,7 @@
StringConstraints,
ValidationInfo,
field_validator,
model_validator,
)
from typing_extensions import Annotated

Expand Down Expand Up @@ -78,31 +81,68 @@ class ReferencesConfig(ModelConfig):
]


class SimpleInterpolationConfig(ModelConfig):
type: Literal["simple"]
length: Annotated[int, Field(default=50, description="", gt=0)]
trial_number: Annotated[int, Field(default=100000, description="", ge=0)]
trial_step: Annotated[float, Field(default=0.01, description="", gt=0)]


class ResInsightInterpolationConfig(ModelConfig):
type: Literal["resinsight"]
class InterpolationConfig(ModelConfig):
type: Annotated[
str,
Field(
default="resinsight",
description="Interpolation type: 'simple' or 'resinsight'.",
),
]
length: Annotated[
int, Field(default=50, description="Simple interpolation only.", gt=0)
]
trial_number: Annotated[
int, Field(default=100000, description="Simple interpolation only.", ge=0)
]
trial_step: Annotated[
float, Field(default=0.01, description="Simple interpolation only.", gt=0)
]
measured_depth_step: Annotated[
float,
Field(
default=5,
description="'Step size used in exporting interpolated well trajectories.",
description="ResInsight interpolation only: Step size used in exporting interpolated well trajectories.",
gt=0,
),
]

@model_validator(mode="after")
def check_type(self) -> InterpolationConfig:
fields_set = self.__pydantic_fields_set__ - {"type"}
if self.type == "resinsight":
fields = ["length", "trial_number", "trial_step"]
if fields_set & set(fields):
msg = f"Interpolation type 'resinsight': fields not allowed: {fields}"
raise ValueError(msg)
elif self.type == "simple":
if fields_set & {"measured_depth_step"}:
msg = "Interpolation type 'simple': 'measured_depth_step' not allowed"
raise ValueError(msg)
else:
msg = f"Unknown interpolation type: {self.type}"
raise ValueError(msg)
return self


class DynamicDomainProperty(ModelConfig):
key: Annotated[
str,
StringConstraints(strip_whitespace=True, strict=True, pattern=r"^[^a-z]+$"),
Field(
description="Keyword representing dynamic cell property in flow simulator which will be accepted in filtering, e.g. PRESSURE."
),
]
min: Annotated[float, Field(description="Minimum value.")]
max: Annotated[float, Field(description="Maximum value.")]


class DomainProperty(ModelConfig):
class StaticDomainProperty(ModelConfig):
key: Annotated[
str,
StringConstraints(strip_whitespace=True, strict=True, pattern=r"^[^a-z]+$"),
Field(
description="Keyword representing a cell property in flow simulator which will be accepted in filtering."
description="Keyword for static (initial) cell property in flow simulator which will be accepted in filtering, e.g. PORO."
),
]
min: Annotated[float, Field(description="Minimum value.")]
Expand All @@ -116,11 +156,11 @@ class PerforationConfig(ModelConfig):
Field(description="Well name."),
]
dynamic: Annotated[
Tuple[DomainProperty, ...],
Tuple[DynamicDomainProperty, ...],
Field(default_factory=tuple, description=""),
]
static: Annotated[
Tuple[DomainProperty, ...],
Tuple[StaticDomainProperty, ...],
Field(default_factory=tuple, description=""),
]
formations: Annotated[
Expand All @@ -132,8 +172,14 @@ class PerforationConfig(ModelConfig):
]


class ResInsightConnectionConfig(ModelConfig):
type: Literal["resinsight"]
class ConnectionConfig(ModelConfig):
type: Annotated[
str,
Field(
default="resinsight",
description="Connection type: currently only 'resinsight'.",
),
]
date: Annotated[
datetime.date,
Field(
Expand All @@ -149,6 +195,13 @@ class ResInsightConnectionConfig(ModelConfig):
]
perforations: Annotated[Tuple[PerforationConfig, ...], Field(description="")]

@model_validator(mode="after")
def check_type(self) -> ConnectionConfig:
if self.type != "resinsight":
msg = f"Unknown interpolation type: {self.type}"
raise ValueError(msg)
return self


class PlatformConfig(ModelConfig):
name: Annotated[str, Field(description="Name for platform.")]
Expand Down Expand Up @@ -212,19 +265,44 @@ class WellConfig(ModelConfig):


class ConfigSchema(ModelConfig):
scales: Annotated[ScalesConfig, Field(description="")]
references: Annotated[ReferencesConfig, Field(description="")]
scales: Annotated[
ScalesConfig,
Field(
description="Scaling lengths for the guide points.",
),
]
references: Annotated[
ReferencesConfig,
Field(
description="Reference points for the guide points.",
),
]
interpolation: Annotated[
Union[SimpleInterpolationConfig, ResInsightInterpolationConfig],
Field(description="Options related to interpolation of guide points."),
InterpolationConfig,
Field(
description="Options related to interpolation of guide points.",
),
]
connections: Annotated[
ResInsightConnectionConfig, Field(description="", default=None)
ConnectionConfig,
Field(
description="Options related to the connections.",
default=None,
),
]
platforms: Annotated[
Tuple[PlatformConfig, ...], Field(default_factory=tuple, description="")
Tuple[PlatformConfig, ...],
Field(
default_factory=tuple,
description="Configuration of the platforms.",
),
]
wells: Annotated[
Tuple[WellConfig, ...],
Field(
description="Configuration of the wells.",
),
]
wells: Annotated[Tuple[WellConfig, ...], Field(description="")]
eclipse_model: Annotated[
Path,
AfterValidator(validate_eclipse_path),
Expand Down
13 changes: 7 additions & 6 deletions src/everest_models/jobs/fm_well_trajectory/resinsight.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import logging
from pathlib import Path
from typing import Any, Dict, Iterable, Optional, Tuple
from typing import Any, Dict, Iterable, Optional, Tuple, Union

import lasio
import pandas
Expand All @@ -10,9 +10,10 @@
from everest_models.jobs.shared.models.phase import PhaseEnum

from .models.config import (
DomainProperty,
ConnectionConfig,
DynamicDomainProperty,
PerforationConfig,
ResInsightConnectionConfig,
StaticDomainProperty,
WellConfig,
)
from .models.data_structs import Trajectory
Expand All @@ -36,7 +37,7 @@ def read_wells(
project: rips.Project,
well_path_folder: Path,
well_names: Iterable[str],
connection: Optional[ResInsightConnectionConfig],
connection: Optional[ConnectionConfig],
) -> None:
project.import_well_paths(
well_path_files=[
Expand All @@ -58,7 +59,7 @@ def read_wells(


def create_well(
connection: ResInsightConnectionConfig,
connection: ConnectionConfig,
well_config: WellConfig,
guide_points: Trajectory,
project: rips.Project,
Expand Down Expand Up @@ -234,7 +235,7 @@ def create_well_logs(
def _filter_properties(
conditions: pandas.Series,
df: pandas.DataFrame,
properties: Tuple[DomainProperty, ...],
properties: Tuple[Union[DynamicDomainProperty, StaticDomainProperty], ...],
) -> pandas.Series:
for property in properties:
if property.min is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import rips

from .models.config import ConfigSchema, ResInsightInterpolationConfig
from .models.config import ConfigSchema
from .outputs import write_well_costs
from .read_trajectories import read_laterals
from .resinsight import (
Expand Down Expand Up @@ -75,7 +75,7 @@ def well_trajectory_resinsight(
) as resinsight:
resinsight.project.load_case(str(eclipse_model.with_suffix(".EGRID")))

if isinstance(config.interpolation, ResInsightInterpolationConfig):
if config.interpolation.type == "resinsight":
# Interpolate trajectories and save smooth trajectories:
well_paths = {
well_config.name: create_well(
Expand Down
Loading

0 comments on commit b0d6a4c

Please sign in to comment.