Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenthoms committed Dec 5, 2024
1 parent 8e01f14 commit 9016ab5
Show file tree
Hide file tree
Showing 12 changed files with 365 additions and 92 deletions.
2 changes: 2 additions & 0 deletions backend_py/primary/primary/routers/well/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def convert_wellbore_header_to_schema(
depthReferenceElevation=drilled_wellbore_header.depth_reference_elevation,
wellborePurpose=(drilled_wellbore_header.wellbore_purpose if drilled_wellbore_header.wellbore_purpose else ""),
wellboreStatus=drilled_wellbore_header.wellbore_status if drilled_wellbore_header.wellbore_status else "",
parentWellbore=drilled_wellbore_header.parent_wellbore if drilled_wellbore_header.parent_wellbore else "",
kickoffDepthMd=drilled_wellbore_header.kickoff_depth_md,
)


Expand Down
19 changes: 17 additions & 2 deletions backend_py/primary/primary/routers/well/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from primary.auth.auth_helper import AuthHelper

from primary.services.ssdl_access.well_access import WellAccess as SsdlWellAccess
from primary.services.wellbore_trajectory_reducer import reduce_child_wellbore_trajectories

from . import schemas
from . import converters
Expand Down Expand Up @@ -43,7 +44,8 @@ async def get_well_trajectories(
# fmt:off
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
field_identifier: str = Query(description="Official field identifier"),
wellbore_uuids:List[str] = Query(None, description="Optional subset of wellbore uuids")
wellbore_uuids:List[str] = Query(None, description="Optional subset of wellbore uuids"),
use_kickoff_depth: bool = Query(False, description="Use kickoff depth to reduce child wellbore trajectory length")
# fmt:on
) -> List[schemas.WellboreTrajectory]:
"""Get well trajectories for field"""
Expand All @@ -56,9 +58,22 @@ async def get_well_trajectories(

wellbore_trajectories = await well_access.get_wellbore_trajectories(wellbore_uuids=wellbore_uuids)

if not use_kickoff_depth:
return [
converters.convert_well_trajectory_to_schema(wellbore_trajectory)
for wellbore_trajectory in wellbore_trajectories
]

# Use kickoff depth to reduce child wellbore trajectory length
wellbore_headers = await well_access.get_wellbore_headers(wellbore_uuids=wellbore_uuids)

adjusted_wellbore_trajectories = reduce_child_wellbore_trajectories(
wellbore_headers=wellbore_headers, wellbore_trajectories=wellbore_trajectories
)

return [
converters.convert_well_trajectory_to_schema(wellbore_trajectory)
for wellbore_trajectory in wellbore_trajectories
for wellbore_trajectory in adjusted_wellbore_trajectories
]


Expand Down
2 changes: 2 additions & 0 deletions backend_py/primary/primary/routers/well/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class WellboreHeader(BaseModel):
depthReferenceElevation: float
wellborePurpose: str
wellboreStatus: str
parentWellbore: str
kickoffDepthMd: float


class WellboreTrajectory(BaseModel):
Expand Down
15 changes: 13 additions & 2 deletions backend_py/primary/primary/services/smda_access/smda_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async def get_stratigraphic_units(self, strat_column_identifier: str) -> List[St
units = [StratigraphicUnit(**result) for result in results]
return units

async def get_wellbore_headers(self) -> List[WellboreHeader]:
async def get_wellbore_headers(self, wellbore_uuids: Optional[List[str]] = None) -> List[WellboreHeader]:
"""
Get wellbore header information for all wellbores in a field.
We need the wellbores with actual survey data, so we must use the wellbore-survey-headers endpoint.
Expand All @@ -68,14 +68,23 @@ async def get_wellbore_headers(self) -> List[WellboreHeader]:
"field_identifier": self._field_identifier,
}

if wellbore_uuids:
params["wellbore_uuid"] = ", ".join(wellbore_uuids)

survey_header_results = await self._smda_get_request(
endpoint=SmdaEndpoints.WELLBORE_SURVEY_HEADERS, params=params
)

if not survey_header_results:
raise NoDataError(f"No wellbore headers found for {self._field_identifier=}.", Service.SMDA)

projection = ["unique_wellbore_identifier", "wellbore_purpose", "wellbore_status"]
projection = [
"unique_wellbore_identifier",
"wellbore_purpose",
"wellbore_status",
"parent_wellbore",
"kickoff_depth_md",
]
params = {
"_projection": ",".join(projection),
"_sort": "unique_wellbore_identifier",
Expand All @@ -89,6 +98,8 @@ async def get_wellbore_headers(self) -> List[WellboreHeader]:
if survey_header["unique_wellbore_identifier"] == wellbore_header["unique_wellbore_identifier"]:
survey_header["wellbore_purpose"] = wellbore_header.get("wellbore_purpose")
survey_header["wellbore_status"] = wellbore_header.get("wellbore_status")
survey_header["parent_wellbore"] = wellbore_header.get("parent_wellbore")
survey_header["kickoff_depth_md"] = wellbore_header.get("kickoff_depth_md")
break

return [WellboreHeader(**result) for result in survey_header_results]
Expand Down
2 changes: 2 additions & 0 deletions backend_py/primary/primary/services/smda_access/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class WellboreHeader(BaseModel):
depth_reference_elevation: float
wellbore_purpose: str | None
wellbore_status: str | None
parent_wellbore: str | None
kickoff_depth_md: float | None


class StratigraphicUnit(BaseModel):
Expand Down
67 changes: 67 additions & 0 deletions backend_py/primary/primary/services/wellbore_trajectory_reducer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import List

from primary.services.smda_access.types import WellboreTrajectory, WellboreHeader


def reduce_child_wellbore_trajectories(
wellbore_headers: List[WellboreHeader], wellbore_trajectories: List[WellboreTrajectory]
) -> List[WellboreTrajectory]:
"""
Reduce the child wellbore trajectories to the parent wellbore trajectory by removing all common
points from the child wellbore trajectory.
Args:
wellbore_headers: List of well headers
wellbore_trajectories: List of wellbore trajectories
Returns:
List of reduced wellbore trajectories
"""
adjusted_wellbore_trajectories: List[WellboreTrajectory] = []

for wellbore_header in wellbore_headers:
trajectory = [x for x in wellbore_trajectories if x.wellbore_uuid == wellbore_header.wellbore_uuid][0]
parent_wellbore = wellbore_header.parent_wellbore
kickoff_md = wellbore_header.kickoff_depth_md

if parent_wellbore is None:
adjusted_wellbore_trajectories.append(trajectory)
continue

# Reduce child wellbore trajectory length
adjusted_trajectory = WellboreTrajectory(
wellbore_uuid=trajectory.wellbore_uuid,
unique_wellbore_identifier=trajectory.unique_wellbore_identifier,
tvd_msl_arr=[],
md_arr=[],
easting_arr=[],
northing_arr=[],
)
for i, md in enumerate(trajectory.md_arr):
if md < kickoff_md:
continue

if md != kickoff_md:
factor = (trajectory.md_arr[i] - kickoff_md) / (trajectory.md_arr[i] - trajectory.md_arr[i - 1])
adjusted_trajectory.md_arr.append(kickoff_md)
adjusted_trajectory.tvd_msl_arr.append(
trajectory.tvd_msl_arr[i - 1] + factor * (trajectory.tvd_msl_arr[i] - trajectory.tvd_msl_arr[i - 1])
)
adjusted_trajectory.easting_arr.append(
trajectory.easting_arr[i - 1] + factor * (trajectory.easting_arr[i] - trajectory.easting_arr[i - 1])
)
adjusted_trajectory.northing_arr.append(
trajectory.northing_arr[i - 1]
+ factor * (trajectory.northing_arr[i] - trajectory.northing_arr[i - 1])
)

adjusted_trajectory.tvd_msl_arr.extend(trajectory.tvd_msl_arr[i:-1])
# What is the convention here? Should we keep the original md or adjust it by kickoff depth?
adjusted_trajectory.md_arr.extend(trajectory.md_arr[i:-1])
adjusted_trajectory.easting_arr.extend(trajectory.easting_arr[i:-1])
adjusted_trajectory.northing_arr.extend(trajectory.northing_arr[i:-1])
break

adjusted_wellbore_trajectories.append(adjusted_trajectory)

return adjusted_wellbore_trajectories
2 changes: 2 additions & 0 deletions frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ module.exports = {
"react/jsx-uses-react": "off", // Import of React is not required anymore in React 17
"react/react-in-jsx-scope": "off", // Import of React is not required anymore in React 17
"no-console": ["error", { allow: ["debug", "info", "warn", "error"] }],
"camelcase": "always",
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 8,
sourceType: "module",
},
settings: {

react: {
version: "detect",
},
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/api/models/WellboreHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ export type WellboreHeader = {
depthReferenceElevation: number;
wellborePurpose: string;
wellboreStatus: string;
parentWellbore: string;
kickoffDepthMd: number;
};

3 changes: 3 additions & 0 deletions frontend/src/api/services/WellService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,22 @@ export class WellService {
* Get well trajectories for field
* @param fieldIdentifier Official field identifier
* @param wellboreUuids Optional subset of wellbore uuids
* @param useKickoffDepth Use kickoff depth to reduce child wellbore trajectory length
* @returns WellboreTrajectory Successful Response
* @throws ApiError
*/
public getWellTrajectories(
fieldIdentifier: string,
wellboreUuids?: Array<string>,
useKickoffDepth: boolean = false,
): CancelablePromise<Array<WellboreTrajectory>> {
return this.httpRequest.request({
method: 'GET',
url: '/well/well_trajectories/',
query: {
'field_identifier': fieldIdentifier,
'wellbore_uuids': wellboreUuids,
'use_kickoff_depth': useKickoffDepth,
},
errors: {
422: `Validation Error`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export class DrilledWellTrajectoriesLayer implements Layer<DrilledWellTrajectori
const promise = queryClient
.fetchQuery({
queryKey,
queryFn: () => apiService.well.getWellTrajectories(fieldIdentifier ?? ""),
queryFn: () => apiService.well.getWellTrajectories(fieldIdentifier ?? "", undefined, false),
staleTime: 1800000, // TODO
gcTime: 1800000,
})
Expand Down
Loading

0 comments on commit 9016ab5

Please sign in to comment.