Skip to content

Commit 07c816e

Browse files
bugfix : crs for vertical wellbore
1 parent ca0065f commit 07c816e

5 files changed

Lines changed: 111 additions & 47 deletions

File tree

energyml-utils/example/attic/arrays_test.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,40 @@ def read_pointset(
378378
return meshes
379379

380380

381+
def read_wellbore_frame_repr_demo_jfr_02_26(
382+
epc_path: str = r"rc/epc/out-galaxy-12-pts.epc",
383+
well_uuid: str = "cfad9cb6-99fe-4172-b560-d2feca75dd9f",
384+
) -> List[AbstractMesh]:
385+
epc = Epc.read_file(f"{epc_path}", read_rels_from_files=False, recompute_rels=False)
386+
387+
frame_repr = epc.get_object_by_uuid(well_uuid)[0]
388+
# print(frame_repr)
389+
# print(epc.get_h5_file_paths(frame_repr))
390+
391+
print(epc.get_h5_file_paths())
392+
393+
print(epc.get_h5_file_paths(frame_repr))
394+
395+
print("Object type: ", type(frame_repr))
396+
397+
meshes = read_mesh_object(energyml_object=frame_repr, workspace=epc)
398+
399+
# Previous result :
400+
# points:
401+
# [[ 0. 0. 0.]
402+
# [ 0. 0. 250.]
403+
# [ 0. 0. 500.]
404+
# [ 0. 0. 750.]
405+
# [ 0. 0. 1000.]]
406+
# line indices:
407+
# [[0 1]
408+
# [1 2]
409+
# [2 3]
410+
# [3 4]]
411+
412+
return meshes
413+
414+
381415
if __name__ == "__main__":
382416
logging.basicConfig(level=logging.DEBUG)
383417

@@ -386,7 +420,8 @@ def read_pointset(
386420
# meshes = read_wellbore_frame_repr()
387421
# meshes = read_representation_set_representation()
388422
# meshes = read_trset()
389-
meshes = read_pointset()
423+
# meshes = read_pointset()
424+
meshes = read_wellbore_frame_repr_demo_jfr_02_26()
390425

391426
print(f"Number of meshes read: {len(meshes)}")
392427

energyml-utils/src/energyml/utils/data/helper.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,12 @@ def get_crs_origin_offset(crs_obj: Any) -> List[float | int]:
311311
return crs_point_offset
312312

313313

314-
def get_datum_information(datum_obj: Any, workspace: Optional[EnergymlStorageInterface] = None):
315-
"From a ObjMdDatum or a ReferencePointInACrs, return x, y, z, z_increas_downward, projected_epsg_code, vertical_epsg_code"
314+
def get_datum_information(
315+
datum_obj: Any, workspace: Optional[EnergymlStorageInterface] = None
316+
) -> Tuple[float, float, float, bool, Optional[str], Optional[str], Optional[Any]]:
317+
"From a ObjMdDatum or a ReferencePointInACrs, return x, y, z, z_increas_downward, projected_epsg_code, vertical_epsg_code, crs object"
316318
if datum_obj is None:
317-
return 0.0, 0.0, 0.0, False, None, None
319+
return 0.0, 0.0, 0.0, False, None, None, None
318320

319321
t_lw = type(datum_obj).__name__.lower()
320322

@@ -333,12 +335,18 @@ def get_datum_information(datum_obj: Any, workspace: Optional[EnergymlStorageInt
333335
z_increasing_downward,
334336
projected_epsg_code,
335337
vertical_epsg_code,
338+
datum_obj,
336339
)
337340
elif "referencepointinacrs" in t_lw:
338341
x = get_object_attribute_rgx(datum_obj, "horizontal_coordinates.coordinate1")
339342
y = get_object_attribute_rgx(datum_obj, "horizontal_coordinates.coordinate2")
340343
z = get_object_attribute_rgx(datum_obj, "vertical_coordinate")
341-
z_increasing_downward = get_object_attribute(datum_obj, "ZIncreasingDownward") or False
344+
z_increasing_downward = False
345+
v_crs_dor = get_object_attribute_rgx(datum_obj, "vertical_crs")
346+
if v_crs_dor is not None and workspace is not None:
347+
v_crs = workspace.get_object(get_obj_uri(v_crs_dor))
348+
if v_crs is not None:
349+
z_increasing_downward = is_z_reversed(v_crs)
342350
p_crs = get_object_attribute(datum_obj, "horizontal_coordinates.crs")
343351
projected_epsg_code = (
344352
get_projected_epsg_code(workspace.get_object(get_obj_uri(p_crs)), workspace)
@@ -354,22 +362,26 @@ def get_datum_information(datum_obj: Any, workspace: Optional[EnergymlStorageInt
354362
z_increasing_downward,
355363
projected_epsg_code,
356364
vertical_epsg_code,
365+
p_crs,
357366
)
358367
elif "mddatum" in t_lw:
359368
x = get_object_attribute_rgx(datum_obj, "location.coordinate1")
360369
y = get_object_attribute_rgx(datum_obj, "location.coordinate2")
361370
z = get_object_attribute_rgx(datum_obj, "location.coordinate3")
362371
crs = get_object_attribute(datum_obj, "LocalCrs")
363-
_, _, _, z_increasing_downward, projected_epsg_code, vertical_epsg_code = get_datum_information(crs, workspace)
372+
_, _, _, z_increasing_downward, projected_epsg_code, vertical_epsg_code, _ = get_datum_information(
373+
crs, workspace
374+
)
364375
return (
365376
float(x) if x is not None else 0.0,
366377
float(y) if y is not None else 0.0,
367378
float(z) if z is not None else 0.0,
368379
z_increasing_downward,
369380
projected_epsg_code,
370381
vertical_epsg_code,
382+
crs,
371383
)
372-
return 0.0, 0.0, 0.0, False, None, None
384+
return 0.0, 0.0, 0.0, False, None, None, None
373385

374386

375387
# ==================================================
@@ -659,7 +671,9 @@ def generate_smooth_trajectory(
659671
return np.array(smooth_points)
660672

661673

662-
def generate_vertical_well_points(wellbore_mds: np.ndarray, head_x: float, head_y: float, head_z: float) -> np.ndarray:
674+
def generate_vertical_well_points(
675+
wellbore_mds: np.ndarray, head_x: float, head_y: float, head_z: float, z_increasing_downward: bool = False
676+
) -> np.ndarray:
663677
"""
664678
Generates local 3D coordinates for a perfectly vertical wellbore.
665679
@@ -684,8 +698,12 @@ def generate_vertical_well_points(wellbore_mds: np.ndarray, head_x: float, head_
684698
# In a vertical well, Z_point = Z_datum + (MD_point - MD_datum_at_0)
685699
# Most of the time, MD at head is 0.
686700
# If wellbore_mds start at 0, Z starts at head_z.
701+
# if z_increasing_downward is False, we add the MD to head_z, otherwise we subtract it.
687702
md_start = wellbore_mds[0]
688-
local_points[:, 2] = head_z + (wellbore_mds - md_start)
703+
if z_increasing_downward:
704+
local_points[:, 2] = head_z - (wellbore_mds - md_start)
705+
else:
706+
local_points[:, 2] = head_z + (wellbore_mds - md_start)
689707

690708
return local_points
691709

energyml-utils/src/energyml/utils/data/mesh.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import re
88
import sys
9+
import traceback
910
import numpy as np
1011
from dataclasses import dataclass, field
1112
from enum import Enum
@@ -780,6 +781,8 @@ def read_wellbore_frame_representation(
780781
trajectory_dor = search_attribute_matching_name(obj=energyml_object, name_rgx="Trajectory")[0]
781782
trajectory_obj = workspace.get_object(get_obj_uri(trajectory_dor))
782783

784+
print(f"Mds {wellbore_frame_mds}")
785+
783786
meshes = read_wellbore_trajectory_representation(
784787
energyml_object=trajectory_obj,
785788
workspace=workspace,
@@ -831,8 +834,8 @@ def read_wellbore_trajectory_representation(
831834
# Get CRS from trajectory geometry if available
832835
try:
833836
crs = workspace.get_object(get_obj_uri(get_object_attribute(energyml_object, "geometry.LocalCrs")))
834-
except Exception as e:
835-
logging.debug(f"Could not get CRS from trajectory geometry")
837+
except Exception:
838+
logging.debug("Could not get CRS from trajectory geometry")
836839

837840
# ==========
838841
# MD Datum
@@ -853,14 +856,24 @@ def read_wellbore_trajectory_representation(
853856
md_datum_obj = workspace.get_object(md_datum_identifier)
854857

855858
if md_datum_obj is not None:
856-
head_x, head_y, head_z, z_increasing_downward, projected_epsg_code, vertical_epsg_code = (
859+
head_x, head_y, head_z, z_increasing_downward, projected_epsg_code, vertical_epsg_code, crs = (
857860
get_datum_information(md_datum_obj, workspace)
858861
)
862+
# if crs is None:
863+
# crs = get_crs_obj(
864+
# context_obj=md_datum_obj,
865+
# path_in_root=".",
866+
# root_obj=energyml_object,
867+
# workspace=workspace,
868+
# )
859869
except Exception as e:
860870
logging.debug(f"Could not get reference point / Datum from trajectory: {e}")
861871

862872
# ==========
863873
well_points = None
874+
logging.debug(
875+
f"wellbore mds : {wellbore_frame_mds}\n\tCRs : {crs}\n\thead x,y,z : {head_x}, {head_y}, {head_z}\n\tz increasing downward : {z_increasing_downward}"
876+
)
864877
try:
865878
x_offset, y_offset, z_offset, (azimuth, azimuth_uom) = get_crs_offsets_and_angle(crs, workspace)
866879
# Try to read parametric Geometry from the trajectory.
@@ -886,11 +899,13 @@ def read_wellbore_trajectory_representation(
886899
head_y=head_y,
887900
head_z=head_z,
888901
wellbore_mds=wellbore_frame_mds,
902+
z_increasing_downward=z_increasing_downward,
889903
)
890904
else:
905+
traceback.print_exc()
891906
raise ValueError(
892907
"Cannot read wellbore trajectory representation: no parametric geometry and no measured depth information available to generate points"
893-
) from e
908+
)
894909

895910
meshes = []
896911
if well_points is not None and len(well_points) > 0:

energyml-utils/src/energyml/utils/epc.py

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,11 +1178,10 @@ def write_array(
11781178
obj = self.get_object_by_identifier(proxy)
11791179

11801180
# Determine which external files to use
1181-
file_paths = (
1182-
[make_path_relative_to_other_file(external_uri, self.epc_file_path)]
1183-
if external_uri
1184-
else self.get_h5_file_paths(obj)
1185-
)
1181+
file_paths = self.get_h5_file_paths(obj)
1182+
if external_uri:
1183+
file_paths.insert(0, make_path_relative_to_other_file(external_uri, self.epc_file_path))
1184+
11861185
if not file_paths or len(file_paths) == 0:
11871186
file_paths = self.external_files_path
11881187

@@ -1284,39 +1283,37 @@ def get_array_metadata(
12841283

12851284
return None
12861285

1287-
def get_h5_file_paths(self, obj: Any) -> List[str]:
1286+
def get_h5_file_paths(self, obj_or_id: Optional[Any] = None) -> List[str]:
12881287
"""
12891288
Get all HDF5 file paths referenced in the EPC file (from rels to external resources)
12901289
:return: list of HDF5 file paths
12911290
"""
12921291

12931292
if self.force_h5_path is not None:
12941293
return [self.force_h5_path]
1294+
h5_paths = set()
12951295

1296-
is_uri = (isinstance(obj, str) and parse_uri(obj) is not None) or isinstance(obj, Uri)
1297-
if is_uri:
1298-
obj = self.get_object_by_identifier(obj)
1296+
if obj_or_id is None:
1297+
return [self.epc_file_path.replace(".epc", ".h5")] if self.epc_file_path else []
12991298

1300-
h5_paths = set()
1299+
obj = self.get_object(obj_or_id) if isinstance(obj_or_id, (str, Uri)) else obj_or_id
13011300

1302-
if isinstance(obj, str):
1303-
obj = self.get_object_by_identifier(obj)
13041301
# for rels in self.additional_rels.get(get_obj_identifier(obj), []):
13051302
for rels in self._rels_cache.get_supplemental_rels(obj):
13061303
if rels.type_value == EPCRelsRelationshipType.EXTERNAL_RESOURCE.get_type():
13071304
h5_paths.add(rels.target)
13081305

1306+
h5_paths = set(make_path_relative_to_filepath_list(list(h5_paths), self.epc_file_path))
1307+
13091308
if len(h5_paths) == 0:
1310-
# search if an h5 file has the same name than the epc file
1309+
# Collect all .h5 files in the EPC file's folder
13111310
epc_folder = self.get_epc_file_folder()
1312-
if epc_folder is not None and self.epc_file_path is not None:
1313-
epc_file_name = os.path.basename(self.epc_file_path)
1314-
epc_file_base, _ = os.path.splitext(epc_file_name)
1315-
possible_h5_path = os.path.join(epc_folder, epc_file_base + ".h5")
1316-
if os.path.exists(possible_h5_path):
1317-
h5_paths.add(possible_h5_path)
1318-
1319-
return make_path_relative_to_filepath_list(list(h5_paths), self.epc_file_path)
1311+
if epc_folder is not None and os.path.isdir(epc_folder):
1312+
for fname in os.listdir(epc_folder):
1313+
if fname.lower().endswith(".h5"):
1314+
h5_paths.add(os.path.join(epc_folder, fname))
1315+
1316+
return list(h5_paths)
13201317

13211318
def get_object_as_dor(self, identifier: str, dor_qualified_type) -> Optional[Any]:
13221319
"""

energyml-utils/src/energyml/utils/epc_stream.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
in_epc_file_path_to_mime_type,
5050
is_core_prop_or_extension_path,
5151
repair_epc_structure_if_not_valid,
52+
get_file_folder,
5253
)
5354
from energyml.utils.storage_interface import (
5455
DataArrayMetadata,
@@ -1391,20 +1392,18 @@ def get_h5_file_paths(self, obj: Union[str, Uri, Any], make_path_absolute_from_e
13911392
except KeyError:
13921393
pass
13931394

1394-
if len(h5_paths) == 0:
1395-
# search if an h5 file has the same name than the epc file
1396-
epc_folder = os.path.dirname(self.epc_file_path)
1397-
if epc_folder is not None and self.epc_file_path is not None:
1398-
epc_file_name = os.path.basename(self.epc_file_path)
1399-
epc_file_base, _ = os.path.splitext(epc_file_name)
1400-
possible_h5_path = os.path.join(epc_folder, epc_file_base + ".h5")
1401-
if os.path.exists(possible_h5_path):
1402-
h5_paths.add(possible_h5_path)
1403-
14041395
if make_path_absolute_from_epc_path:
1405-
return make_path_relative_to_filepath_list(list(h5_paths), self.epc_file_path)
1406-
else:
1407-
return list(h5_paths)
1396+
h5_paths = set(make_path_relative_to_filepath_list(list(h5_paths), self.epc_file_path))
1397+
1398+
if len(h5_paths) == 0:
1399+
# Collect all .h5 files in the EPC file's folder
1400+
epc_folder = get_file_folder(self.epc_file_path)
1401+
if epc_folder is not None and os.path.isdir(epc_folder):
1402+
for fname in os.listdir(epc_folder):
1403+
if fname.lower().endswith(".h5"):
1404+
h5_paths.add(os.path.join(epc_folder, fname))
1405+
1406+
return list(h5_paths)
14081407

14091408
# ________ ___ __________ __ _________________ ______ ____ _____
14101409
# / ____/ / / | / ___/ ___/ / |/ / ____/_ __/ / / / __ \/ __ \/ ___/

0 commit comments

Comments
 (0)