pyetp 0.0.45__py3-none-any.whl → 0.0.47__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- energistics/__init__.py +0 -0
- energistics/etp/__init__.py +0 -0
- energistics/etp/v12/__init__.py +0 -0
- energistics/etp/v12/datatypes/__init__.py +25 -0
- energistics/etp/v12/datatypes/data_array_types/__init__.py +27 -0
- energistics/etp/v12/datatypes/object/__init__.py +22 -0
- energistics/etp/v12/protocol/__init__.py +0 -0
- energistics/etp/v12/protocol/core/__init__.py +19 -0
- energistics/etp/v12/protocol/data_array/__init__.py +51 -0
- energistics/etp/v12/protocol/dataspace/__init__.py +23 -0
- energistics/etp/v12/protocol/discovery/__init__.py +21 -0
- energistics/etp/v12/protocol/store/__init__.py +27 -0
- energistics/etp/v12/protocol/transaction/__init__.py +27 -0
- pyetp/__init__.py +1 -2
- pyetp/_version.py +2 -2
- pyetp/client.py +426 -306
- pyetp/errors.py +39 -0
- pyetp/uri.py +3 -1
- pyetp/utils_arrays.py +1 -7
- pyetp/utils_xml.py +1 -6
- {pyetp-0.0.45.dist-info → pyetp-0.0.47.dist-info}/METADATA +8 -3
- pyetp-0.0.47.dist-info/RECORD +39 -0
- {pyetp-0.0.45.dist-info → pyetp-0.0.47.dist-info}/WHEEL +1 -1
- {pyetp-0.0.45.dist-info → pyetp-0.0.47.dist-info}/top_level.txt +2 -0
- rddms_io/__init__.py +0 -0
- rddms_io/client.py +1234 -0
- rddms_io/data_types.py +11 -0
- resqml_objects/epc_readers.py +3 -7
- resqml_objects/parsers.py +18 -5
- resqml_objects/serializers.py +25 -2
- resqml_objects/surface_helpers.py +295 -0
- resqml_objects/v201/generated.py +582 -19
- resqml_objects/v201/utils.py +38 -0
- pyetp-0.0.45.dist-info/RECORD +0 -21
- {pyetp-0.0.45.dist-info → pyetp-0.0.47.dist-info}/licenses/LICENSE.md +0 -0
resqml_objects/v201/generated.py
CHANGED
|
@@ -6,12 +6,22 @@ See: https://xsdata.readthedocs.io/
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import datetime
|
|
10
|
+
import re
|
|
11
|
+
import uuid
|
|
12
|
+
import warnings
|
|
9
13
|
from dataclasses import dataclass, field
|
|
10
14
|
from enum import Enum
|
|
11
|
-
from typing import Any
|
|
15
|
+
from typing import Annotated, Any, Self, Type
|
|
12
16
|
|
|
17
|
+
import numpy as np
|
|
18
|
+
import numpy.typing as npt
|
|
13
19
|
from xsdata.models.datatype import XmlDate, XmlDateTime, XmlPeriod
|
|
14
20
|
|
|
21
|
+
resqml_schema_version = "2.0.1"
|
|
22
|
+
common_schema_version = "2.0"
|
|
23
|
+
OBJ_TYPE_PATTERN = re.compile(r"type=(?P<obj_type>\w+)$")
|
|
24
|
+
|
|
15
25
|
|
|
16
26
|
class APIGammaRayUom(Enum):
|
|
17
27
|
"""
|
|
@@ -747,15 +757,19 @@ class Citation:
|
|
|
747
757
|
"white_space": "collapse",
|
|
748
758
|
}
|
|
749
759
|
)
|
|
750
|
-
creation: XmlDateTime = field(
|
|
760
|
+
creation: XmlDateTime | datetime.datetime = field(
|
|
761
|
+
default_factory=lambda: XmlDateTime.from_datetime(
|
|
762
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
763
|
+
),
|
|
751
764
|
metadata={
|
|
752
765
|
"name": "Creation",
|
|
753
766
|
"type": "Element",
|
|
754
767
|
"namespace": "http://www.energistics.org/energyml/data/commonv2",
|
|
755
768
|
"required": True,
|
|
756
|
-
}
|
|
769
|
+
},
|
|
757
770
|
)
|
|
758
771
|
format: str = field(
|
|
772
|
+
default="",
|
|
759
773
|
metadata={
|
|
760
774
|
"name": "Format",
|
|
761
775
|
"type": "Element",
|
|
@@ -764,7 +778,7 @@ class Citation:
|
|
|
764
778
|
"min_length": 1,
|
|
765
779
|
"max_length": 256,
|
|
766
780
|
"white_space": "collapse",
|
|
767
|
-
}
|
|
781
|
+
},
|
|
768
782
|
)
|
|
769
783
|
editor: None | str = field(
|
|
770
784
|
default=None,
|
|
@@ -777,7 +791,7 @@ class Citation:
|
|
|
777
791
|
"white_space": "collapse",
|
|
778
792
|
},
|
|
779
793
|
)
|
|
780
|
-
last_update: None | XmlDateTime = field(
|
|
794
|
+
last_update: None | XmlDateTime | datetime.datetime = field(
|
|
781
795
|
default=None,
|
|
782
796
|
metadata={
|
|
783
797
|
"name": "LastUpdate",
|
|
@@ -816,6 +830,21 @@ class Citation:
|
|
|
816
830
|
},
|
|
817
831
|
)
|
|
818
832
|
|
|
833
|
+
def __post_init__(self) -> None:
|
|
834
|
+
# Delayed to avoid circular import. Fix once the ETP-client is made
|
|
835
|
+
# indepent of the RESQML-objects.
|
|
836
|
+
from pyetp._version import version
|
|
837
|
+
|
|
838
|
+
if not self.format:
|
|
839
|
+
self.format = f"equinor:pyetp:{version}"
|
|
840
|
+
|
|
841
|
+
# Let the user pass in the creation time as a Python datetime-object
|
|
842
|
+
if isinstance(self.creation, datetime.datetime):
|
|
843
|
+
self.creation = XmlDateTime.from_datetime(self.creation)
|
|
844
|
+
|
|
845
|
+
if isinstance(self.last_update, datetime.datetime):
|
|
846
|
+
self.last_update = XmlDateTime.from_datetime(self.last_update)
|
|
847
|
+
|
|
819
848
|
|
|
820
849
|
@dataclass(slots=True, kw_only=True)
|
|
821
850
|
class CustomData:
|
|
@@ -912,8 +941,153 @@ class DataObjectReference:
|
|
|
912
941
|
},
|
|
913
942
|
)
|
|
914
943
|
|
|
915
|
-
|
|
916
|
-
|
|
944
|
+
@staticmethod
|
|
945
|
+
def get_content_type_string(
|
|
946
|
+
obj: AbstractResqmlDataObject | Type[AbstractResqmlDataObject],
|
|
947
|
+
) -> str:
|
|
948
|
+
"""
|
|
949
|
+
Static method constructing a RESQML v2.0.1 or EML v2.0 content type
|
|
950
|
+
string based on the XML namespace of the provided object. The format of
|
|
951
|
+
the content type string for RESQML v2.0.1 is:
|
|
952
|
+
|
|
953
|
+
application/x-resqml+xml;version=2.0.1;type={object-type}
|
|
954
|
+
|
|
955
|
+
and for EML v2.0:
|
|
956
|
+
|
|
957
|
+
application/x-eml+xml;version=2.0;type={object-type}
|
|
958
|
+
|
|
959
|
+
where `object-type` should correspond to the XSD type of the object.
|
|
960
|
+
For example for a `obj_Grid2dRepresentation`-object this is exactly
|
|
961
|
+
`obj_Grid2dRepresentation`.
|
|
962
|
+
|
|
963
|
+
See Energistics Identifier Specification 4.0 (it is downloaded
|
|
964
|
+
alongside the RESQML v2.0.1 standard) section 4.1 for the
|
|
965
|
+
documentation of this format.
|
|
966
|
+
|
|
967
|
+
Parameters
|
|
968
|
+
----------
|
|
969
|
+
obj: AbstractResqmlDataObject | Type[AbstractResqmlDataObject]
|
|
970
|
+
An instance or type that is a subclass of
|
|
971
|
+
`AbstractResqmlDataObject`.
|
|
972
|
+
|
|
973
|
+
Returns
|
|
974
|
+
-------
|
|
975
|
+
str
|
|
976
|
+
The content type string.
|
|
977
|
+
"""
|
|
978
|
+
|
|
979
|
+
# Get class object instead of the instance.
|
|
980
|
+
if type(obj) is not type:
|
|
981
|
+
obj = type(obj)
|
|
982
|
+
|
|
983
|
+
namespace = getattr(obj.Meta, "namespace", None) or getattr(
|
|
984
|
+
obj.Meta, "target_namespace"
|
|
985
|
+
)
|
|
986
|
+
|
|
987
|
+
if namespace == "http://www.energistics.org/energyml/data/resqmlv2":
|
|
988
|
+
return (
|
|
989
|
+
f"application/x-resqml+xml;version={resqml_schema_version};"
|
|
990
|
+
f"type={obj.__name__}"
|
|
991
|
+
)
|
|
992
|
+
elif namespace == "http://www.energistics.org/energyml/data/commonv2":
|
|
993
|
+
return (
|
|
994
|
+
f"application/x-eml+xml;version={common_schema_version};"
|
|
995
|
+
f"type={obj.__name__}"
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
raise NotImplementedError(
|
|
999
|
+
f"Namespace {namespace} from object {obj} is not supported"
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
@classmethod
|
|
1003
|
+
def from_object(
|
|
1004
|
+
cls,
|
|
1005
|
+
obj: AbstractResqmlDataObject,
|
|
1006
|
+
uuid_authority: None | str = None,
|
|
1007
|
+
version_string: None | str = None,
|
|
1008
|
+
) -> Self:
|
|
1009
|
+
"""
|
|
1010
|
+
Class method setting up a `DataObjectReference` from a RESQML-object
|
|
1011
|
+
instance (subclass of `AbstractResqmlDataObject`). This populates the
|
|
1012
|
+
mandatory fields from the `citation` field of the object.
|
|
1013
|
+
|
|
1014
|
+
Parameters
|
|
1015
|
+
----------
|
|
1016
|
+
obj: AbstractResqmlDataObject
|
|
1017
|
+
A subclass of the `AbstractResqmlDataObject` which contains a
|
|
1018
|
+
`citation`-field.
|
|
1019
|
+
uuid_authority: None | str
|
|
1020
|
+
See documentation of `DataObjectReference`. Default is `None`.
|
|
1021
|
+
version_string: None | str
|
|
1022
|
+
See documentation of `DataObjectReference`. Default is `None`.
|
|
1023
|
+
|
|
1024
|
+
Returns
|
|
1025
|
+
-------
|
|
1026
|
+
Self
|
|
1027
|
+
An instance of `DataObjectReference` with reference information on
|
|
1028
|
+
`obj`.
|
|
1029
|
+
"""
|
|
1030
|
+
content_type = DataObjectReference.get_content_type_string(obj)
|
|
1031
|
+
|
|
1032
|
+
return cls(
|
|
1033
|
+
content_type=content_type,
|
|
1034
|
+
title=obj.citation.title,
|
|
1035
|
+
uuid=obj.uuid,
|
|
1036
|
+
uuid_authority=uuid_authority,
|
|
1037
|
+
version_string=version_string,
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
def get_etp_data_object_uri(self, dataspace_path_or_uri: str) -> str:
|
|
1041
|
+
"""
|
|
1042
|
+
Method that sets up a valid ETP data object uri from a
|
|
1043
|
+
`DataObjectReference`-instance. This is a helper function for easier
|
|
1044
|
+
querying towards an ETP server when downloading parts of a model at a
|
|
1045
|
+
time.
|
|
1046
|
+
|
|
1047
|
+
Parameters
|
|
1048
|
+
----------
|
|
1049
|
+
dataspace_path_or_uri: str
|
|
1050
|
+
Either a full dataspace uri on the form `"eml:///"` or
|
|
1051
|
+
`"eml:///dataspace('foo/bar')"`, or just the dataspace path (or
|
|
1052
|
+
name) – which looking at the previous two examples – is `""`
|
|
1053
|
+
(empty) or "foo/bar".
|
|
1054
|
+
|
|
1055
|
+
Returns
|
|
1056
|
+
-------
|
|
1057
|
+
An ETP data object uri that be used to look up an object on an ETP
|
|
1058
|
+
server.
|
|
1059
|
+
"""
|
|
1060
|
+
|
|
1061
|
+
domain_version = ""
|
|
1062
|
+
|
|
1063
|
+
if self.content_type.startswith("application/x-resqml+xml"):
|
|
1064
|
+
domain_version = "resqml20"
|
|
1065
|
+
elif self.content_type.startswith("application/x-eml+xml"):
|
|
1066
|
+
domain_version = "eml20"
|
|
1067
|
+
else:
|
|
1068
|
+
raise NotImplementedError(
|
|
1069
|
+
f"Qualified type for '{self.content_type}' is not implemented"
|
|
1070
|
+
)
|
|
1071
|
+
|
|
1072
|
+
m = re.search(OBJ_TYPE_PATTERN, self.content_type)
|
|
1073
|
+
|
|
1074
|
+
if m is None:
|
|
1075
|
+
raise ValueError("Content type string does not contain a valid object name")
|
|
1076
|
+
|
|
1077
|
+
obj_type = m.group("obj_type")
|
|
1078
|
+
|
|
1079
|
+
if dataspace_path_or_uri.startswith("eml:///"):
|
|
1080
|
+
dataspace_uri = dataspace_path_or_uri
|
|
1081
|
+
elif not dataspace_path_or_uri:
|
|
1082
|
+
# Only two forward slashes (!!!) as the combination with the
|
|
1083
|
+
# `data_object_part` adds an extra forward slash.
|
|
1084
|
+
dataspace_uri = "eml://"
|
|
1085
|
+
else:
|
|
1086
|
+
dataspace_uri = f"eml:///dataspace('{dataspace_path_or_uri}')"
|
|
1087
|
+
|
|
1088
|
+
data_object_part = f"{domain_version}.{obj_type}({self.uuid})"
|
|
1089
|
+
|
|
1090
|
+
return f"{dataspace_uri}/{data_object_part}"
|
|
917
1091
|
|
|
918
1092
|
|
|
919
1093
|
class DataTransferSpeedUom(Enum):
|
|
@@ -9545,7 +9719,7 @@ class Timestamp:
|
|
|
9545
9719
|
class Meta:
|
|
9546
9720
|
target_namespace = "http://www.energistics.org/energyml/data/resqmlv2"
|
|
9547
9721
|
|
|
9548
|
-
date_time: XmlDateTime = field(
|
|
9722
|
+
date_time: XmlDateTime | datetime.datetime = field(
|
|
9549
9723
|
metadata={
|
|
9550
9724
|
"name": "DateTime",
|
|
9551
9725
|
"type": "Element",
|
|
@@ -9562,6 +9736,10 @@ class Timestamp:
|
|
|
9562
9736
|
},
|
|
9563
9737
|
)
|
|
9564
9738
|
|
|
9739
|
+
def __post_init__(self) -> None:
|
|
9740
|
+
if isinstance(self.date_time, datetime.datetime):
|
|
9741
|
+
self.date_time = XmlDateTime.from_datetime(self.date_time)
|
|
9742
|
+
|
|
9565
9743
|
|
|
9566
9744
|
@dataclass(slots=True, kw_only=True)
|
|
9567
9745
|
class AbstractObject_Type:
|
|
@@ -9659,12 +9837,16 @@ class DateTime:
|
|
|
9659
9837
|
class Meta:
|
|
9660
9838
|
namespace = "http://www.isotc211.org/2005/gco"
|
|
9661
9839
|
|
|
9662
|
-
value: XmlDateTime = field(
|
|
9840
|
+
value: XmlDateTime | datetime.datetime = field(
|
|
9663
9841
|
metadata={
|
|
9664
9842
|
"required": True,
|
|
9665
9843
|
}
|
|
9666
9844
|
)
|
|
9667
9845
|
|
|
9846
|
+
def __post_init__(self) -> None:
|
|
9847
|
+
if isinstance(self.value, datetime.datetime):
|
|
9848
|
+
self.value = XmlDateTime.from_datetime(self.value)
|
|
9849
|
+
|
|
9668
9850
|
|
|
9669
9851
|
@dataclass(slots=True, kw_only=True)
|
|
9670
9852
|
class Real:
|
|
@@ -10043,18 +10225,23 @@ class AbstractObject_1:
|
|
|
10043
10225
|
},
|
|
10044
10226
|
)
|
|
10045
10227
|
schema_version: str = field(
|
|
10228
|
+
# We set the schema_version in the __post_init__ if it is empty by
|
|
10229
|
+
# default.
|
|
10230
|
+
default="",
|
|
10046
10231
|
metadata={
|
|
10047
10232
|
"name": "schemaVersion",
|
|
10048
10233
|
"type": "Attribute",
|
|
10049
10234
|
"required": True,
|
|
10050
|
-
}
|
|
10235
|
+
},
|
|
10051
10236
|
)
|
|
10052
10237
|
uuid: str = field(
|
|
10238
|
+
# We add a uuid by default, if it is not provided.
|
|
10239
|
+
default_factory=lambda: str(uuid.uuid4()),
|
|
10053
10240
|
metadata={
|
|
10054
10241
|
"type": "Attribute",
|
|
10055
10242
|
"required": True,
|
|
10056
10243
|
"pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}",
|
|
10057
|
-
}
|
|
10244
|
+
},
|
|
10058
10245
|
)
|
|
10059
10246
|
object_version: None | str = field(
|
|
10060
10247
|
default=None,
|
|
@@ -10067,6 +10254,58 @@ class AbstractObject_1:
|
|
|
10067
10254
|
},
|
|
10068
10255
|
)
|
|
10069
10256
|
|
|
10257
|
+
def __post_init__(self) -> None:
|
|
10258
|
+
if not self.schema_version:
|
|
10259
|
+
namespace = getattr(self.Meta, "namespace", None) or getattr(
|
|
10260
|
+
self.Meta, "target_namespace"
|
|
10261
|
+
)
|
|
10262
|
+
|
|
10263
|
+
if namespace == "http://www.energistics.org/energyml/data/resqmlv2":
|
|
10264
|
+
self.schema_version = resqml_schema_version
|
|
10265
|
+
elif namespace == "http://www.energistics.org/energyml/data/commonv2":
|
|
10266
|
+
self.schema_version = common_schema_version
|
|
10267
|
+
else:
|
|
10268
|
+
raise NotImplementedError(
|
|
10269
|
+
f"Namespace {namespace} from object {self} has no default schema "
|
|
10270
|
+
"version. Provide this manually as keyword argument when "
|
|
10271
|
+
"constructing the object."
|
|
10272
|
+
)
|
|
10273
|
+
|
|
10274
|
+
@classmethod
|
|
10275
|
+
def get_domain_version(cls) -> str:
|
|
10276
|
+
namespace = getattr(cls.Meta, "namespace", None) or getattr(
|
|
10277
|
+
cls.Meta, "target_namespace"
|
|
10278
|
+
)
|
|
10279
|
+
|
|
10280
|
+
if namespace == "http://www.energistics.org/energyml/data/resqmlv2":
|
|
10281
|
+
return "resqml20"
|
|
10282
|
+
elif namespace == "http://www.energistics.org/energyml/data/commonv2":
|
|
10283
|
+
return "eml20"
|
|
10284
|
+
|
|
10285
|
+
raise NotImplementedError(
|
|
10286
|
+
f"Namespace {namespace} from object {cls} is not supported"
|
|
10287
|
+
)
|
|
10288
|
+
|
|
10289
|
+
@classmethod
|
|
10290
|
+
def get_qualified_type(cls) -> str:
|
|
10291
|
+
return cls.get_domain_version() + f".{cls.__name__}"
|
|
10292
|
+
|
|
10293
|
+
def get_etp_data_object_uri(self, dataspace_path_or_uri: str) -> str:
|
|
10294
|
+
qualified_type = self.get_qualified_type()
|
|
10295
|
+
identifier = (
|
|
10296
|
+
self.uuid
|
|
10297
|
+
if self.object_version is None
|
|
10298
|
+
else f"uuid={self.uuid},version='{self.object_version}'"
|
|
10299
|
+
)
|
|
10300
|
+
data_object_part = f"{qualified_type}({identifier})"
|
|
10301
|
+
|
|
10302
|
+
if not dataspace_path_or_uri or dataspace_path_or_uri == "eml:///":
|
|
10303
|
+
return f"eml:///{data_object_part}"
|
|
10304
|
+
elif dataspace_path_or_uri.startswith("eml:///dataspace"):
|
|
10305
|
+
return f"{dataspace_path_or_uri}/{data_object_part}"
|
|
10306
|
+
|
|
10307
|
+
return f"eml:///dataspace('{dataspace_path_or_uri}')/{data_object_part}"
|
|
10308
|
+
|
|
10070
10309
|
|
|
10071
10310
|
@dataclass(slots=True, kw_only=True)
|
|
10072
10311
|
class ActivityOfRadioactivityMeasure:
|
|
@@ -16947,6 +17186,62 @@ class Point3dZValueArray(AbstractPoint3dArray):
|
|
|
16947
17186
|
}
|
|
16948
17187
|
)
|
|
16949
17188
|
|
|
17189
|
+
@classmethod
|
|
17190
|
+
def from_regular_surface(
|
|
17191
|
+
cls,
|
|
17192
|
+
epc_external_part_reference: obj_EpcExternalPartReference,
|
|
17193
|
+
path_in_hdf_file: str,
|
|
17194
|
+
shape: tuple[int, int],
|
|
17195
|
+
origin: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
17196
|
+
spacing: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
17197
|
+
unit_vec_1: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
17198
|
+
unit_vec_2: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
17199
|
+
) -> Self:
|
|
17200
|
+
supporting_geometry = Point3dLatticeArray(
|
|
17201
|
+
origin=Point3d(
|
|
17202
|
+
coordinate1=float(origin[0]),
|
|
17203
|
+
coordinate2=float(origin[1]),
|
|
17204
|
+
coordinate3=0.0,
|
|
17205
|
+
),
|
|
17206
|
+
offset=[
|
|
17207
|
+
Point3dOffset(
|
|
17208
|
+
offset=Point3d(
|
|
17209
|
+
coordinate1=float(unit_vec_1[0]),
|
|
17210
|
+
coordinate2=float(unit_vec_1[1]),
|
|
17211
|
+
coordinate3=0.0,
|
|
17212
|
+
),
|
|
17213
|
+
spacing=DoubleConstantArray(
|
|
17214
|
+
value=float(spacing[0]),
|
|
17215
|
+
# TODO: Figure out how we should treat the spacing! The
|
|
17216
|
+
# documentation states that it should be N - 1 for an
|
|
17217
|
+
# array of N elements (that is, it counts the number of
|
|
17218
|
+
# spaces between elements). However, we have seen cases
|
|
17219
|
+
# where this is instead set to N.
|
|
17220
|
+
count=int(shape[0]) - 1,
|
|
17221
|
+
),
|
|
17222
|
+
),
|
|
17223
|
+
Point3dOffset(
|
|
17224
|
+
offset=Point3d(
|
|
17225
|
+
coordinate1=float(unit_vec_2[0]),
|
|
17226
|
+
coordinate2=float(unit_vec_2[1]),
|
|
17227
|
+
coordinate3=0.0,
|
|
17228
|
+
),
|
|
17229
|
+
spacing=DoubleConstantArray(
|
|
17230
|
+
value=float(spacing[1]),
|
|
17231
|
+
count=int(shape[1]) - 1,
|
|
17232
|
+
),
|
|
17233
|
+
),
|
|
17234
|
+
],
|
|
17235
|
+
)
|
|
17236
|
+
zvalues = DoubleHdf5Array(
|
|
17237
|
+
values=Hdf5Dataset(
|
|
17238
|
+
path_in_hdf_file=path_in_hdf_file,
|
|
17239
|
+
hdf_proxy=DataObjectReference.from_object(epc_external_part_reference),
|
|
17240
|
+
),
|
|
17241
|
+
)
|
|
17242
|
+
|
|
17243
|
+
return cls(supporting_geometry=supporting_geometry, zvalues=zvalues)
|
|
17244
|
+
|
|
16950
17245
|
|
|
16951
17246
|
@dataclass(slots=True, kw_only=True)
|
|
16952
17247
|
class ResqmlJaggedArray:
|
|
@@ -17958,12 +18253,13 @@ class obj_EpcExternalPartReference(AbstractCitedDataObject):
|
|
|
17958
18253
|
target_namespace = "http://www.energistics.org/energyml/data/commonv2"
|
|
17959
18254
|
|
|
17960
18255
|
mime_type: str = field(
|
|
18256
|
+
default="application/x-hdf5",
|
|
17961
18257
|
metadata={
|
|
17962
18258
|
"name": "MimeType",
|
|
17963
18259
|
"type": "Element",
|
|
17964
18260
|
"namespace": "http://www.energistics.org/energyml/data/commonv2",
|
|
17965
18261
|
"required": True,
|
|
17966
|
-
}
|
|
18262
|
+
},
|
|
17967
18263
|
)
|
|
17968
18264
|
|
|
17969
18265
|
|
|
@@ -18584,6 +18880,32 @@ class PointGeometry(AbstractGeometry):
|
|
|
18584
18880
|
},
|
|
18585
18881
|
)
|
|
18586
18882
|
|
|
18883
|
+
@classmethod
|
|
18884
|
+
def from_regular_surface(
|
|
18885
|
+
cls,
|
|
18886
|
+
crs: AbstractLocal3dCrs,
|
|
18887
|
+
epc_external_part_reference: obj_EpcExternalPartReference,
|
|
18888
|
+
path_in_hdf_file: str,
|
|
18889
|
+
shape: tuple[int, int],
|
|
18890
|
+
origin: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
18891
|
+
spacing: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
18892
|
+
unit_vec_1: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
18893
|
+
unit_vec_2: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
18894
|
+
) -> Self:
|
|
18895
|
+
local_crs = DataObjectReference.from_object(crs)
|
|
18896
|
+
|
|
18897
|
+
points = Point3dZValueArray.from_regular_surface(
|
|
18898
|
+
epc_external_part_reference=epc_external_part_reference,
|
|
18899
|
+
path_in_hdf_file=path_in_hdf_file,
|
|
18900
|
+
shape=shape,
|
|
18901
|
+
origin=origin,
|
|
18902
|
+
spacing=spacing,
|
|
18903
|
+
unit_vec_1=unit_vec_1,
|
|
18904
|
+
unit_vec_2=unit_vec_2,
|
|
18905
|
+
)
|
|
18906
|
+
|
|
18907
|
+
return cls(local_crs=local_crs, points=points)
|
|
18908
|
+
|
|
18587
18909
|
|
|
18588
18910
|
@dataclass(slots=True, kw_only=True)
|
|
18589
18911
|
class Regrid:
|
|
@@ -19427,44 +19749,49 @@ class AbstractLocal3dCrs(AbstractResqmlDataObject):
|
|
|
19427
19749
|
target_namespace = "http://www.energistics.org/energyml/data/resqmlv2"
|
|
19428
19750
|
|
|
19429
19751
|
yoffset: float = field(
|
|
19752
|
+
default=0.0,
|
|
19430
19753
|
metadata={
|
|
19431
19754
|
"name": "YOffset",
|
|
19432
19755
|
"type": "Element",
|
|
19433
19756
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19434
19757
|
"required": True,
|
|
19435
|
-
}
|
|
19758
|
+
},
|
|
19436
19759
|
)
|
|
19437
19760
|
zoffset: float = field(
|
|
19761
|
+
default=0.0,
|
|
19438
19762
|
metadata={
|
|
19439
19763
|
"name": "ZOffset",
|
|
19440
19764
|
"type": "Element",
|
|
19441
19765
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19442
19766
|
"required": True,
|
|
19443
|
-
}
|
|
19767
|
+
},
|
|
19444
19768
|
)
|
|
19445
19769
|
areal_rotation: PlaneAngleMeasure = field(
|
|
19770
|
+
default_factory=lambda: PlaneAngleMeasure(value=0.0, uom=PlaneAngleUom.RAD),
|
|
19446
19771
|
metadata={
|
|
19447
19772
|
"name": "ArealRotation",
|
|
19448
19773
|
"type": "Element",
|
|
19449
19774
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19450
19775
|
"required": True,
|
|
19451
|
-
}
|
|
19776
|
+
},
|
|
19452
19777
|
)
|
|
19453
19778
|
projected_axis_order: AxisOrder2d = field(
|
|
19779
|
+
default=AxisOrder2d.EASTING_NORTHING,
|
|
19454
19780
|
metadata={
|
|
19455
19781
|
"name": "ProjectedAxisOrder",
|
|
19456
19782
|
"type": "Element",
|
|
19457
19783
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19458
19784
|
"required": True,
|
|
19459
|
-
}
|
|
19785
|
+
},
|
|
19460
19786
|
)
|
|
19461
19787
|
projected_uom: LengthUom = field(
|
|
19788
|
+
default=LengthUom.M,
|
|
19462
19789
|
metadata={
|
|
19463
19790
|
"name": "ProjectedUom",
|
|
19464
19791
|
"type": "Element",
|
|
19465
19792
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19466
19793
|
"required": True,
|
|
19467
|
-
}
|
|
19794
|
+
},
|
|
19468
19795
|
)
|
|
19469
19796
|
vertical_uom: LengthUom = field(
|
|
19470
19797
|
metadata={
|
|
@@ -19475,20 +19802,22 @@ class AbstractLocal3dCrs(AbstractResqmlDataObject):
|
|
|
19475
19802
|
}
|
|
19476
19803
|
)
|
|
19477
19804
|
xoffset: float = field(
|
|
19805
|
+
default=0.0,
|
|
19478
19806
|
metadata={
|
|
19479
19807
|
"name": "XOffset",
|
|
19480
19808
|
"type": "Element",
|
|
19481
19809
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19482
19810
|
"required": True,
|
|
19483
|
-
}
|
|
19811
|
+
},
|
|
19484
19812
|
)
|
|
19485
19813
|
zincreasing_downward: bool = field(
|
|
19814
|
+
default=True,
|
|
19486
19815
|
metadata={
|
|
19487
19816
|
"name": "ZIncreasingDownward",
|
|
19488
19817
|
"type": "Element",
|
|
19489
19818
|
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
19490
19819
|
"required": True,
|
|
19491
|
-
}
|
|
19820
|
+
},
|
|
19492
19821
|
)
|
|
19493
19822
|
vertical_crs: AbstractVerticalCrs = field(
|
|
19494
19823
|
metadata={
|
|
@@ -19736,6 +20065,39 @@ class Grid2dPatch(Patch):
|
|
|
19736
20065
|
}
|
|
19737
20066
|
)
|
|
19738
20067
|
|
|
20068
|
+
@classmethod
|
|
20069
|
+
def from_regular_surface(
|
|
20070
|
+
cls,
|
|
20071
|
+
crs: AbstractLocal3dCrs,
|
|
20072
|
+
epc_external_part_reference: obj_EpcExternalPartReference,
|
|
20073
|
+
path_in_hdf_file: str,
|
|
20074
|
+
shape: tuple[int, int],
|
|
20075
|
+
origin: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
20076
|
+
spacing: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
20077
|
+
unit_vec_1: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
20078
|
+
unit_vec_2: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
20079
|
+
patch_index: int = 0,
|
|
20080
|
+
) -> Self:
|
|
20081
|
+
geometry = PointGeometry.from_regular_surface(
|
|
20082
|
+
crs=crs,
|
|
20083
|
+
epc_external_part_reference=epc_external_part_reference,
|
|
20084
|
+
path_in_hdf_file=path_in_hdf_file,
|
|
20085
|
+
shape=shape,
|
|
20086
|
+
origin=origin,
|
|
20087
|
+
spacing=spacing,
|
|
20088
|
+
unit_vec_1=unit_vec_1,
|
|
20089
|
+
unit_vec_2=unit_vec_2,
|
|
20090
|
+
)
|
|
20091
|
+
|
|
20092
|
+
return cls(
|
|
20093
|
+
patch_index=patch_index,
|
|
20094
|
+
# Rows for NumPy-arrays in C-major ordering.
|
|
20095
|
+
slowest_axis_count=shape[0],
|
|
20096
|
+
# Columns for NumPy-arrays in C-major ordering.
|
|
20097
|
+
fastest_axis_count=shape[1],
|
|
20098
|
+
geometry=geometry,
|
|
20099
|
+
)
|
|
20100
|
+
|
|
19739
20101
|
|
|
19740
20102
|
@dataclass(slots=True, kw_only=True)
|
|
19741
20103
|
class HorizontalPlaneGeometry(AbstractPlaneGeometry):
|
|
@@ -21782,6 +22144,17 @@ class obj_LocalDepth3dCrs(AbstractLocal3dCrs):
|
|
|
21782
22144
|
class Meta:
|
|
21783
22145
|
target_namespace = "http://www.energistics.org/energyml/data/resqmlv2"
|
|
21784
22146
|
|
|
22147
|
+
# Overwriting the super-field to set a default.
|
|
22148
|
+
vertical_uom: LengthUom = field(
|
|
22149
|
+
default=LengthUom.M,
|
|
22150
|
+
metadata={
|
|
22151
|
+
"name": "VerticalUom",
|
|
22152
|
+
"type": "Element",
|
|
22153
|
+
"namespace": "http://www.energistics.org/energyml/data/resqmlv2",
|
|
22154
|
+
"required": True,
|
|
22155
|
+
},
|
|
22156
|
+
)
|
|
22157
|
+
|
|
21785
22158
|
|
|
21786
22159
|
@dataclass(slots=True, kw_only=True)
|
|
21787
22160
|
class obj_LocalTime3dCrs(AbstractLocal3dCrs):
|
|
@@ -23639,6 +24012,196 @@ class obj_Grid2dRepresentation(AbstractSurfaceRepresentation):
|
|
|
23639
24012
|
}
|
|
23640
24013
|
)
|
|
23641
24014
|
|
|
24015
|
+
def get_xy_grid(
|
|
24016
|
+
self, crs: AbstractLocal3dCrs | None = None
|
|
24017
|
+
) -> tuple[
|
|
24018
|
+
npt.NDArray[np.float64],
|
|
24019
|
+
npt.NDArray[np.float64],
|
|
24020
|
+
]:
|
|
24021
|
+
"""
|
|
24022
|
+
Method constructing the `X`- and `Y`-grids for a regular surface. This
|
|
24023
|
+
currently only works for `obj_Grid2dRepresentation`-objects that
|
|
24024
|
+
represent regular surfaces. That is where the grids are specified using
|
|
24025
|
+
an origin, spacings, number of elements and unit vectors. Otherwise the
|
|
24026
|
+
`X`- and `Y`-grids are stored as arrays on an ETP server or in an
|
|
24027
|
+
hdf5-file. The function also takes in a local crs that can be
|
|
24028
|
+
transformed (translated and rotated) from a global crs. The method
|
|
24029
|
+
treats any rotation and translation in the grid as an _active
|
|
24030
|
+
transformation_, and any transformation in the local crs as a _passive
|
|
24031
|
+
transformation_.
|
|
24032
|
+
|
|
24033
|
+
Parameters
|
|
24034
|
+
----------
|
|
24035
|
+
crs: AbstractLocal3dCrs
|
|
24036
|
+
A subclass of `AbstractLocal3dCrs`. It is used to correct for a
|
|
24037
|
+
potential passive transformation done by the crs. The crs does not
|
|
24038
|
+
have to be the same as referenced by the grid-object, but if it
|
|
24039
|
+
does not match a warning is raised. Setting `crs=None` avoids any
|
|
24040
|
+
transformation from the crs. Default is `None`.
|
|
24041
|
+
|
|
24042
|
+
Returns
|
|
24043
|
+
-------
|
|
24044
|
+
tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]
|
|
24045
|
+
A pair of `X`- and `Y`-grids that gives the `x` and `y` coordinates
|
|
24046
|
+
to the surface described by the grid-object. For an unrotated
|
|
24047
|
+
surface this corresponds to a meshgrid.
|
|
24048
|
+
"""
|
|
24049
|
+
points = self.grid2d_patch.geometry.points
|
|
24050
|
+
|
|
24051
|
+
if not isinstance(points, Point3dZValueArray):
|
|
24052
|
+
raise NotImplementedError(
|
|
24053
|
+
"We do not support constructing the X, Y grid for points of type "
|
|
24054
|
+
f"{points.__class__.__name__}"
|
|
24055
|
+
)
|
|
24056
|
+
|
|
24057
|
+
sg = points.supporting_geometry
|
|
24058
|
+
if not isinstance(sg, Point3dLatticeArray):
|
|
24059
|
+
raise NotImplementedError(
|
|
24060
|
+
"We do not support constructing the X, Y grid for a supporting "
|
|
24061
|
+
f"geometry of type {sg.__class__.__name__}"
|
|
24062
|
+
)
|
|
24063
|
+
|
|
24064
|
+
from resqml_objects.surface_helpers import RegularGridParameters
|
|
24065
|
+
|
|
24066
|
+
shape = (
|
|
24067
|
+
self.grid2d_patch.slowest_axis_count,
|
|
24068
|
+
self.grid2d_patch.fastest_axis_count,
|
|
24069
|
+
)
|
|
24070
|
+
origin = sg.origin
|
|
24071
|
+
offsets = sg.offset
|
|
24072
|
+
|
|
24073
|
+
ori = np.array(
|
|
24074
|
+
[
|
|
24075
|
+
origin.coordinate1,
|
|
24076
|
+
origin.coordinate2,
|
|
24077
|
+
]
|
|
24078
|
+
)
|
|
24079
|
+
dr = np.array(
|
|
24080
|
+
[
|
|
24081
|
+
offsets[0].spacing.value,
|
|
24082
|
+
offsets[1].spacing.value,
|
|
24083
|
+
]
|
|
24084
|
+
)
|
|
24085
|
+
|
|
24086
|
+
unit_vectors = np.array(
|
|
24087
|
+
[
|
|
24088
|
+
[offsets[0].offset.coordinate1, offsets[1].offset.coordinate1],
|
|
24089
|
+
[offsets[0].offset.coordinate2, offsets[1].offset.coordinate2],
|
|
24090
|
+
]
|
|
24091
|
+
)
|
|
24092
|
+
|
|
24093
|
+
crs_angle = 0.0
|
|
24094
|
+
crs_offset = np.array([0.0, 0.0])
|
|
24095
|
+
|
|
24096
|
+
if crs is not None:
|
|
24097
|
+
if crs.uuid != self.grid2d_patch.geometry.local_crs.uuid:
|
|
24098
|
+
warnings.warn(
|
|
24099
|
+
f"The provided crs has a different uuid '{crs.citation.uuid}' "
|
|
24100
|
+
" than the referenced crs "
|
|
24101
|
+
f"'{self.grid2d_patch.geometry.local_crs.uuid}'."
|
|
24102
|
+
)
|
|
24103
|
+
|
|
24104
|
+
# NOTE: We assume that coordinate1 (coordinate2) corresponds to
|
|
24105
|
+
# xoffset (yoffset) in the CRS, and that they share the same units.
|
|
24106
|
+
crs_offset[0] = crs.xoffset
|
|
24107
|
+
crs_offset[1] = crs.yoffset
|
|
24108
|
+
|
|
24109
|
+
crs_angle_unit = PlaneAngleUom(crs.areal_rotation.uom)
|
|
24110
|
+
|
|
24111
|
+
match crs_angle_unit:
|
|
24112
|
+
case PlaneAngleUom.RAD:
|
|
24113
|
+
crs_angle = crs.areal_rotation.value
|
|
24114
|
+
case PlaneAngleUom.DEGA:
|
|
24115
|
+
crs_angle = np.deg2rad(crs.areal_rotation.value)
|
|
24116
|
+
case _:
|
|
24117
|
+
raise NotImplementedError(
|
|
24118
|
+
f"No conversion from {crs_angle_unit} to radians implemented"
|
|
24119
|
+
)
|
|
24120
|
+
|
|
24121
|
+
rgp = RegularGridParameters(
|
|
24122
|
+
shape=shape,
|
|
24123
|
+
origin=ori,
|
|
24124
|
+
spacing=dr,
|
|
24125
|
+
unit_vectors=unit_vectors,
|
|
24126
|
+
crs_angle=crs_angle,
|
|
24127
|
+
crs_offset=crs_offset,
|
|
24128
|
+
)
|
|
24129
|
+
|
|
24130
|
+
return rgp.to_xy_grid(to_global_crs=True)
|
|
24131
|
+
|
|
24132
|
+
@classmethod
|
|
24133
|
+
def from_regular_surface(
|
|
24134
|
+
cls,
|
|
24135
|
+
citation: Citation,
|
|
24136
|
+
crs: AbstractLocal3dCrs,
|
|
24137
|
+
epc_external_part_reference: obj_EpcExternalPartReference,
|
|
24138
|
+
shape: tuple[int, int],
|
|
24139
|
+
origin: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
24140
|
+
spacing: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
24141
|
+
unit_vec_1: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
24142
|
+
unit_vec_2: Annotated[npt.NDArray[np.float64], dict(shape=(2,))],
|
|
24143
|
+
patch_index: int = 0,
|
|
24144
|
+
path_in_hdf_file: str = "",
|
|
24145
|
+
uuid: str | uuid.UUID | None = None,
|
|
24146
|
+
surface_role: SurfaceRole | str = SurfaceRole.MAP,
|
|
24147
|
+
boundaries: list[PatchBoundaries] | None = None,
|
|
24148
|
+
represented_interpretation: AbstractFeatureInterpretation | None = None,
|
|
24149
|
+
extra_metadata: list[NameValuePair] | None = None,
|
|
24150
|
+
custom_data: CustomData | None = None,
|
|
24151
|
+
object_version: str | None = None,
|
|
24152
|
+
aliases: list[ObjectAlias] | None = None,
|
|
24153
|
+
) -> Self:
|
|
24154
|
+
"""
|
|
24155
|
+
Class method that sets up an `obj_Grid2dRepresentation`-object for a
|
|
24156
|
+
regular surface described by the eight parameters (seven free
|
|
24157
|
+
parameters) `shape`, `origin`, `dr` and `unit_vectors`, and the
|
|
24158
|
+
necessary (a local crs, and an epc-reference file) and/or optional
|
|
24159
|
+
metadata from RESQML.
|
|
24160
|
+
"""
|
|
24161
|
+
|
|
24162
|
+
if uuid is None:
|
|
24163
|
+
# Cursed solution as the `uuid`-argument overwrites the top-level
|
|
24164
|
+
# import of the standard-library `uuid`.
|
|
24165
|
+
import uuid
|
|
24166
|
+
|
|
24167
|
+
uuid = str(uuid.uuid4())
|
|
24168
|
+
|
|
24169
|
+
surface_role = SurfaceRole(surface_role)
|
|
24170
|
+
boundaries = boundaries or []
|
|
24171
|
+
extra_metadata = extra_metadata or []
|
|
24172
|
+
aliases = aliases or []
|
|
24173
|
+
path_in_hdf_file = path_in_hdf_file or f"/RESQML/{uuid}/zvalues"
|
|
24174
|
+
|
|
24175
|
+
if represented_interpretation is not None:
|
|
24176
|
+
represented_interpretation = DataObjectReference.from_object(
|
|
24177
|
+
represented_interpretation
|
|
24178
|
+
)
|
|
24179
|
+
|
|
24180
|
+
grid2d_patch = Grid2dPatch.from_regular_surface(
|
|
24181
|
+
crs=crs,
|
|
24182
|
+
epc_external_part_reference=epc_external_part_reference,
|
|
24183
|
+
path_in_hdf_file=path_in_hdf_file,
|
|
24184
|
+
shape=shape,
|
|
24185
|
+
origin=origin,
|
|
24186
|
+
spacing=spacing,
|
|
24187
|
+
unit_vec_1=unit_vec_1,
|
|
24188
|
+
unit_vec_2=unit_vec_2,
|
|
24189
|
+
patch_index=patch_index,
|
|
24190
|
+
)
|
|
24191
|
+
|
|
24192
|
+
return cls(
|
|
24193
|
+
citation=citation,
|
|
24194
|
+
aliases=aliases,
|
|
24195
|
+
custom_data=custom_data,
|
|
24196
|
+
uuid=uuid,
|
|
24197
|
+
object_version=object_version,
|
|
24198
|
+
surface_role=surface_role,
|
|
24199
|
+
grid2d_patch=grid2d_patch,
|
|
24200
|
+
boundaries=boundaries,
|
|
24201
|
+
represented_interpretation=represented_interpretation,
|
|
24202
|
+
extra_metadata=extra_metadata,
|
|
24203
|
+
)
|
|
24204
|
+
|
|
23642
24205
|
|
|
23643
24206
|
@dataclass(slots=True, kw_only=True)
|
|
23644
24207
|
class obj_Grid2dSetRepresentation(AbstractSurfaceRepresentation):
|