zonevu 1.0.0__tar.gz

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.
Files changed (79) hide show
  1. zonevu-1.0.0/PKG-INFO +24 -0
  2. zonevu-1.0.0/README.md +5 -0
  3. zonevu-1.0.0/pyproject.toml +29 -0
  4. zonevu-1.0.0/zonevu/DataModels/Company.py +18 -0
  5. zonevu-1.0.0/zonevu/DataModels/Curve.py +59 -0
  6. zonevu-1.0.0/zonevu/DataModels/DataModel.py +40 -0
  7. zonevu-1.0.0/zonevu/DataModels/Formation.py +55 -0
  8. zonevu-1.0.0/zonevu/DataModels/Geomodels/DataGrid.py +27 -0
  9. zonevu-1.0.0/zonevu/DataModels/Geomodels/Geomodel.py +27 -0
  10. zonevu-1.0.0/zonevu/DataModels/Geomodels/SimpleGrid.py +26 -0
  11. zonevu-1.0.0/zonevu/DataModels/Geomodels/Structure.py +16 -0
  12. zonevu-1.0.0/zonevu/DataModels/Geomodels/__init__.py +0 -0
  13. zonevu-1.0.0/zonevu/DataModels/Geospatial/Coordinate.py +22 -0
  14. zonevu-1.0.0/zonevu/DataModels/Geospatial/Crs.py +44 -0
  15. zonevu-1.0.0/zonevu/DataModels/Geospatial/Enums.py +8 -0
  16. zonevu-1.0.0/zonevu/DataModels/Geospatial/GeoBox.py +44 -0
  17. zonevu-1.0.0/zonevu/DataModels/Geospatial/GeoLocation.py +52 -0
  18. zonevu-1.0.0/zonevu/DataModels/Geospatial/GridCorner.py +14 -0
  19. zonevu-1.0.0/zonevu/DataModels/Geospatial/GridGeometry.py +91 -0
  20. zonevu-1.0.0/zonevu/DataModels/Geospatial/__init__.py +0 -0
  21. zonevu-1.0.0/zonevu/DataModels/Geosteering/Conditioning.py +42 -0
  22. zonevu-1.0.0/zonevu/DataModels/Geosteering/CurveDef.py +26 -0
  23. zonevu-1.0.0/zonevu/DataModels/Geosteering/Horizon.py +50 -0
  24. zonevu-1.0.0/zonevu/DataModels/Geosteering/Interpretation.py +35 -0
  25. zonevu-1.0.0/zonevu/DataModels/Geosteering/Pick.py +27 -0
  26. zonevu-1.0.0/zonevu/DataModels/Geosteering/__init__.py +0 -0
  27. zonevu-1.0.0/zonevu/DataModels/Helpers.py +49 -0
  28. zonevu-1.0.0/zonevu/DataModels/Map/UserLayer.py +43 -0
  29. zonevu-1.0.0/zonevu/DataModels/Map/__init__.py +0 -0
  30. zonevu-1.0.0/zonevu/DataModels/Note.py +20 -0
  31. zonevu-1.0.0/zonevu/DataModels/NoteCategory.py +10 -0
  32. zonevu-1.0.0/zonevu/DataModels/Project.py +80 -0
  33. zonevu-1.0.0/zonevu/DataModels/Station.py +23 -0
  34. zonevu-1.0.0/zonevu/DataModels/StratColumn.py +19 -0
  35. zonevu-1.0.0/zonevu/DataModels/Styles/Colors.py +31 -0
  36. zonevu-1.0.0/zonevu/DataModels/Styles/FillStyle.py +22 -0
  37. zonevu-1.0.0/zonevu/DataModels/Styles/LineStyle.py +22 -0
  38. zonevu-1.0.0/zonevu/DataModels/Styles/__init__.py +0 -0
  39. zonevu-1.0.0/zonevu/DataModels/Survey.py +86 -0
  40. zonevu-1.0.0/zonevu/DataModels/Well.py +196 -0
  41. zonevu-1.0.0/zonevu/DataModels/WellEntry.py +24 -0
  42. zonevu-1.0.0/zonevu/DataModels/Wellbore.py +71 -0
  43. zonevu-1.0.0/zonevu/DataModels/Welllog.py +50 -0
  44. zonevu-1.0.0/zonevu/DataModels/Welltop.py +24 -0
  45. zonevu-1.0.0/zonevu/DataModels/__init__.py +0 -0
  46. zonevu-1.0.0/zonevu/Samples/DataMgmt/CopyGeosteeringInterp.py +64 -0
  47. zonevu-1.0.0/zonevu/Samples/DataMgmt/CopyLog.py +106 -0
  48. zonevu-1.0.0/zonevu/Samples/DataMgmt/CopySurvey.py +72 -0
  49. zonevu-1.0.0/zonevu/Samples/DataMgmt/CopyWell.py +43 -0
  50. zonevu-1.0.0/zonevu/Samples/DataMgmt/DeleteProjectWells.py +50 -0
  51. zonevu-1.0.0/zonevu/Samples/DataMgmt/DeleteWell.py +24 -0
  52. zonevu-1.0.0/zonevu/Samples/DataMgmt/GeomodelSample.py +64 -0
  53. zonevu-1.0.0/zonevu/Samples/DataMgmt/ProjectCopy.py +34 -0
  54. zonevu-1.0.0/zonevu/Samples/DataMgmt/__init__.py +0 -0
  55. zonevu-1.0.0/zonevu/Samples/Plot/CrossSection.py +138 -0
  56. zonevu-1.0.0/zonevu/Samples/Plot/__init__.py +0 -0
  57. zonevu-1.0.0/zonevu/Samples/__init__.py +0 -0
  58. zonevu-1.0.0/zonevu/Services/Client.py +156 -0
  59. zonevu-1.0.0/zonevu/Services/CompanyService.py +45 -0
  60. zonevu-1.0.0/zonevu/Services/CoordinatesService.py +186 -0
  61. zonevu-1.0.0/zonevu/Services/CurveService.py +37 -0
  62. zonevu-1.0.0/zonevu/Services/EndPoint.py +43 -0
  63. zonevu-1.0.0/zonevu/Services/Error.py +39 -0
  64. zonevu-1.0.0/zonevu/Services/FormationService.py +44 -0
  65. zonevu-1.0.0/zonevu/Services/GeomodelService.py +102 -0
  66. zonevu-1.0.0/zonevu/Services/GeosteeringService.py +67 -0
  67. zonevu-1.0.0/zonevu/Services/MapService.py +52 -0
  68. zonevu-1.0.0/zonevu/Services/NoteService.py +68 -0
  69. zonevu-1.0.0/zonevu/Services/ProjectService.py +91 -0
  70. zonevu-1.0.0/zonevu/Services/SurveyService.py +62 -0
  71. zonevu-1.0.0/zonevu/Services/Utils.py +17 -0
  72. zonevu-1.0.0/zonevu/Services/WellData.py +56 -0
  73. zonevu-1.0.0/zonevu/Services/WellEntryService.py +24 -0
  74. zonevu-1.0.0/zonevu/Services/WellService.py +198 -0
  75. zonevu-1.0.0/zonevu/Services/WelllogService.py +94 -0
  76. zonevu-1.0.0/zonevu/Services/WelltopService.py +53 -0
  77. zonevu-1.0.0/zonevu/Services/__init__.py +0 -0
  78. zonevu-1.0.0/zonevu/Zonevu.py +119 -0
  79. zonevu-1.0.0/zonevu/__init__.py +0 -0
zonevu-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.1
2
+ Name: zonevu
3
+ Version: 1.0.0
4
+ Summary: ZoneVu Web API Python Package
5
+ Home-page: https://www.ubiterra.com/
6
+ License: MIT
7
+ Author: Ubiterra
8
+ Author-email: support@ubiterra.com
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Description-Content-Type: text/markdown
18
+
19
+ # ZoneVu Web API Package
20
+
21
+ This is the ZoneVu Web API interface package by Ubiterra. Access
22
+ [Zonevu Knowledge Base](https://help.ubiterra.com)
23
+ for documentation about using this package.
24
+
zonevu-1.0.0/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # ZoneVu Web API Package
2
+
3
+ This is the ZoneVu Web API interface package by Ubiterra. Access
4
+ [Zonevu Knowledge Base](https://help.ubiterra.com)
5
+ for documentation about using this package.
@@ -0,0 +1,29 @@
1
+ [tool.poetry]
2
+ name = "zonevu"
3
+ version = "1.0.0"
4
+ description = "ZoneVu Web API Python Package"
5
+ authors = ["Ubiterra <support@ubiterra.com>"]
6
+ readme = "README.md"
7
+ packages = [{include = "zonevu"}]
8
+ license = "MIT"
9
+ homepage = "https://www.ubiterra.com/"
10
+ classifiers = [
11
+ "License :: OSI Approved :: MIT License",
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Topic :: Software Development :: Libraries"
17
+ ]
18
+ #disable-git = "true"
19
+
20
+ [tool.poetry.dependencies]
21
+ python = "^3.11"
22
+
23
+ [build-system]
24
+ requires = ["poetry-core"]
25
+ build-backend = "poetry.core.masonry.api"
26
+
27
+
28
+
29
+
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json, LetterCase
3
+
4
+
5
+ @dataclass_json(letter_case=LetterCase.PASCAL)
6
+ @dataclass
7
+ class Company:
8
+ Version: str = '' # API Version
9
+ RuntimeVersion: str = '?' # ZoneVu server runtime version
10
+ CompanyName: str = ''
11
+ Notice: str = ''
12
+
13
+ def printNotice(self):
14
+ print("Zonevu Web API Version %s. Zonevu Server Version %s." % (self.Version, self.RuntimeVersion))
15
+ print(self.Notice)
16
+ print("ZoneVu account '%s'" % self.CompanyName)
17
+ print()
18
+
@@ -0,0 +1,59 @@
1
+ import json
2
+ from typing import Optional
3
+ from dataclasses import dataclass, field
4
+ from dataclasses_json import dataclass_json, LetterCase
5
+ from .DataModel import DataModel
6
+ import numpy as np
7
+ from strenum import StrEnum
8
+
9
+
10
+ class AppMnemonicCodeEnum(StrEnum):
11
+ NotSet = "NotSet"
12
+ DEPT = "DEPT" # "Hole depth (MD)"
13
+ GR = "GR" # "Gamma ray"
14
+ ROP = "ROP" # "Rate of penetration"
15
+ WOB = "WOB" # "Weight on bit"
16
+ INCL = "INCL" # "Inclination"
17
+ AZIM = "AZIM" # "Azimuth"
18
+ GAS = "GAS" # "Total Gas"
19
+ BIT = "BIT" # "Bit depth"
20
+ GRDEPT = "GRDEPT" # "Gamma ray depth"
21
+ DENS = "DENS" # "Density"
22
+ RESS = "RESS" # "Shallow Resistivity"
23
+ RESM = "RESM" # "Medium Resistivity"
24
+ RESD = "RESD" # "Deep Resistivity"
25
+ DTC = "DTC" # "Compressional Sonic Travel Time"
26
+ DTS = "DTS" # "Shear Sonic Travel Time"
27
+ SP = "SP" # "Spontaneous Potential"
28
+ PHIN = "PHIN" # "Neutron Porosity"
29
+ PHID = "PHID" # "Density Porosity"
30
+ NMR = "NMR" # "Nuclear Magnetic Resonance"
31
+ PE = "PE" # "Photoelectric cross section"
32
+ AGR = "AGR" # "Azimuthal Gamma Ray"
33
+ PHIE = "PHIE" # "Porosity"
34
+ SW = "SW" # "Water Saturation"
35
+ VSHL = "VSHL" # "Shale Content"
36
+ HCP = "HCP" # "HydocarbonPorosity"
37
+ TIME = "TIME" # "Time (UTC)"
38
+
39
+ @classmethod
40
+ def _missing_(cls, value):
41
+ return AppMnemonicCodeEnum.NotSet
42
+
43
+
44
+ @dataclass_json(letter_case=LetterCase.PASCAL)
45
+ @dataclass
46
+ class Curve(DataModel):
47
+ description: Optional[str] = None
48
+ mnemonic: str = ''
49
+ system_mnemonic: AppMnemonicCodeEnum = field(default_factory=lambda: AppMnemonicCodeEnum.NotSet)
50
+ unit: Optional[str] = None
51
+ samples: Optional[np.ndarray] = None # numpy float array
52
+ registered: bool = True
53
+
54
+ @classmethod
55
+ def from_dict(cls, dict_obj):
56
+ instance = cls(**dict_obj)
57
+ return instance
58
+
59
+
@@ -0,0 +1,40 @@
1
+ from typing import Optional, Type
2
+ from dataclasses import dataclass, field, fields
3
+ from dataclasses_json import dataclass_json, LetterCase
4
+ from strenum import StrEnum
5
+
6
+
7
+ class ChangeAgentEnum(StrEnum):
8
+ Unknown = 'Unknown'
9
+ GuiCreate = 'GuiCreate'
10
+ GuiImport = 'GuiImport'
11
+ GuiBulkImport = 'GuiBulkImport'
12
+ WebApi = 'WebApi'
13
+
14
+
15
+ class WellElevationUnitsEnum(StrEnum):
16
+ Undefined = 'Undefined'
17
+ Meters = 'Meters'
18
+ Feet = 'Feet'
19
+ FeetUS = 'FeetUS'
20
+
21
+
22
+ @dataclass_json(letter_case=LetterCase.PASCAL)
23
+ @dataclass
24
+ class DataModel:
25
+ id: int = -1 # Mandatory
26
+ name: Optional[str] = None
27
+ row_version: Optional[str] = None
28
+
29
+ def merge_from(self, source: 'DataModel'):
30
+ self.__dict__.update(source.__dict__)
31
+
32
+ def copy_ids_from(self, source: 'DataModel'):
33
+ self.id = source.id
34
+
35
+ @staticmethod
36
+ def merge_lists(dst_list: list['DataModel'], src_list: list['DataModel']):
37
+ for (dst, src) in zip(dst_list, src_list):
38
+ if dst is not None and src is not None:
39
+ dst.copy_ids_from(src)
40
+
@@ -0,0 +1,55 @@
1
+ from typing import Optional
2
+ from dataclasses import dataclass, field
3
+ from dataclasses_json import dataclass_json, LetterCase, config
4
+ from .DataModel import DataModel
5
+ from strenum import StrEnum, PascalCaseStrEnum
6
+
7
+
8
+ class GeoPeriodEnum(StrEnum):
9
+ Quaternary = 'Quaternary',
10
+ Neogene = 'Neogene',
11
+ Paleogene = 'Paleogene',
12
+ Cretaceous = 'Cretaceous',
13
+ Jurassic = 'Jurassic',
14
+ Triassic = 'Triassic',
15
+ Permian = 'Permian',
16
+ Carboniferous = 'Carboniferous',
17
+ Devonian = 'Devonian',
18
+ Silurian = 'Silurian',
19
+ Ordovician = 'Ordovician',
20
+ Cambrian = 'Cambrian',
21
+ Precambrian = 'Precambrian'
22
+
23
+
24
+ class LithologyTypeEnum(PascalCaseStrEnum):
25
+ Unset = 'Unset',
26
+ Sandstone = 'Sandstone',
27
+ Shale = 'Shale',
28
+ Limestone = 'Limestone',
29
+ Dolomite = 'Dolomite',
30
+ Chalk = 'Chalk',
31
+ Marl = 'Marl',
32
+ MudstoneRich = 'MudstoneRich',
33
+ MudstoneLean = 'MudstoneLean',
34
+ Bentonite = 'Bentonite',
35
+ Coal = 'Coal',
36
+ Chert = 'Chert',
37
+ Anhydrite = 'Anhydrite',
38
+ Siltstone = 'Siltstone',
39
+ ShalySand = 'ShalySand'
40
+
41
+
42
+ @dataclass_json(letter_case=LetterCase.PASCAL)
43
+ @dataclass
44
+ class Formation(DataModel):
45
+ formation_name: Optional[str] = None
46
+ member_name: Optional[str] = None
47
+ strat_col_order: int = -1
48
+ symbol: str = ''
49
+ color: Optional[str] = None
50
+ description: Optional[str] = None
51
+ period: Optional[GeoPeriodEnum] = None
52
+ lithology_type: Optional[LithologyTypeEnum] = None
53
+
54
+ def __post_init__(self):
55
+ self.name = self.formation_name
@@ -0,0 +1,27 @@
1
+ from typing import Optional
2
+ from enum import StrEnum
3
+ from dataclasses import dataclass
4
+ from dataclasses_json import dataclass_json, LetterCase
5
+ from zonevu.zonevu.DataModels.DataModel import DataModel
6
+ from zonevu.zonevu.DataModels.Geospatial.GridGeometry import GridGeometry
7
+ import numpy as np
8
+
9
+
10
+ class GridUsageEnum(StrEnum):
11
+ Undefined = 'Undefined'
12
+ Structural = 'Structural'
13
+ Isopach = 'Isopach'
14
+ Attribute = 'Attribute'
15
+
16
+
17
+ @dataclass_json(letter_case=LetterCase.PASCAL)
18
+ @dataclass
19
+ class DataGrid(DataModel):
20
+ geometry: GridGeometry = None
21
+ description: Optional[str] = None
22
+ usage: GridUsageEnum = GridUsageEnum.Undefined
23
+ average_value: Optional[float] = None
24
+ min_value: Optional[float] = None
25
+ max_value: Optional[float] = None
26
+ z_values: Optional[np.ndarray] = None # numpy 32-bit (single precision float array). Must be 32-bit floats!
27
+
@@ -0,0 +1,27 @@
1
+ from typing import Optional
2
+ from dataclasses import dataclass, field
3
+ from dataclasses_json import dataclass_json, LetterCase
4
+ from zonevu.zonevu.DataModels.DataModel import DataModel, ChangeAgentEnum
5
+ from zonevu.zonevu.DataModels.Geomodels.DataGrid import DataGrid
6
+ from zonevu.zonevu.DataModels.Geomodels.Structure import Structure
7
+ from datetime import datetime
8
+ from zonevu.zonevu.DataModels.Helpers import MakeIsodataOptionalField
9
+
10
+
11
+ @dataclass_json(letter_case=LetterCase.PASCAL)
12
+ @dataclass
13
+ class Geomodel(DataModel):
14
+ external_id: Optional[str] = None
15
+ external_source: Optional[str] = None
16
+ creator: Optional[str] = None
17
+ change_agent: ChangeAgentEnum = ChangeAgentEnum.Unknown
18
+ creation_date: Optional[datetime] = MakeIsodataOptionalField()
19
+ last_modified_date: Optional[datetime] = MakeIsodataOptionalField()
20
+ division_id: int = 0
21
+ division: str = ''
22
+ strat_column_id: int = 0
23
+ strat_column_name: str = ''
24
+ description: Optional[str] = None
25
+ data_grids: list[DataGrid] = field(default_factory=list[DataGrid])
26
+ structures: list[Structure] = field(default_factory=list[Structure])
27
+
@@ -0,0 +1,26 @@
1
+ import numpy as np
2
+ from typing import List
3
+ from dataclasses import dataclass
4
+ from ..Geospatial.Coordinate import Coordinate
5
+ from ..Geospatial.Crs import CrsSpec
6
+
7
+
8
+ @dataclass
9
+ class SimpleGrid:
10
+ """
11
+ Represents a simple grid.
12
+ Use float('-inf') to represent empty grid values
13
+ """
14
+ name: str
15
+ origin: Coordinate # x,y coordinate of grid origin
16
+ inclination: float # rotation of grid clockwise
17
+ dx: float # grid spacing in x-direction, when not rotated by inclination
18
+ dy: float # grid spacing in y-direction
19
+ num_rows: int # number of rows in grid. Rows are laid out along the x-direction (non-rotated)
20
+ num_cols: int # number of columns in grid. Columns are laid out along the y-direction (non-rotated)
21
+ crs: CrsSpec # The projected coordinate system of the x,y origin.
22
+ z_values: List[float] # Z values of grid, as a 1-D array of 32-bit floats in row major order
23
+
24
+
25
+
26
+
@@ -0,0 +1,16 @@
1
+ from typing import Optional
2
+ from dataclasses import dataclass
3
+ from dataclasses_json import dataclass_json, LetterCase
4
+ from zonevu.zonevu.DataModels.DataModel import DataModel
5
+ from zonevu.zonevu.DataModels.Geospatial.GridGeometry import GridGeometry
6
+ import numpy as np
7
+
8
+
9
+ @dataclass_json(letter_case=LetterCase.PASCAL)
10
+ @dataclass
11
+ class Structure(DataModel):
12
+ formation_id: int = 0
13
+ formation_name: str = ''
14
+ geometry: GridGeometry = None
15
+ description: Optional[str] = None
16
+ z_values: Optional[np.ndarray] = None # numpy float array
File without changes
@@ -0,0 +1,22 @@
1
+ from dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json, LetterCase
3
+
4
+
5
+ @dataclass_json(letter_case=LetterCase.PASCAL)
6
+ @dataclass
7
+ class Coordinate:
8
+ x: float = 0
9
+ y: float = 0
10
+
11
+ # def rotate(self, angle: float) -> 'Coordinate':
12
+ # """
13
+ # Rotates this point around the origin by an angle
14
+ # @param angle: angle from x-axis in radians
15
+ # @return: the rotated point
16
+ # """
17
+ # x = self.x * math.cos(angle) - self.y * math.sin(angle)
18
+ # y = self.x * math.sin(angle) + self.y * math.cos(angle)
19
+ # return Coordinate(x, y)
20
+ #
21
+ # def __add__(self, other: 'Coordinate') -> 'Coordinate':
22
+ # return Coordinate(self.x + other.x, self.y + other.y)
@@ -0,0 +1,44 @@
1
+ from typing import Optional
2
+ from dataclasses import dataclass
3
+ from dataclasses_json import dataclass_json, LetterCase
4
+ from zonevu.zonevu.DataModels.Geospatial.Enums import DistanceUnitsEnum
5
+
6
+
7
+ # Projected coordinate system specification
8
+ @dataclass_json(letter_case=LetterCase.PASCAL)
9
+ @dataclass
10
+ class CrsSpec:
11
+ """
12
+ Used to specify a projected coordinate system
13
+ The EPSG code takes preference if both are specified.
14
+ The Units data member if provided overrides the default units of the specified coordinate system
15
+ """
16
+ epsg_code: Optional[int] = None
17
+ projection: Optional[str] = None # DotSpatial string for projection
18
+ zone: Optional[str] = None # DotSpatial string for zone
19
+ units: Optional[DistanceUnitsEnum] = None # Distance units override.
20
+
21
+ @classmethod
22
+ def from_epsg_code(cls, code: int, units: DistanceUnitsEnum = None) -> 'CrsSpec':
23
+ return cls(code, None, None, units)
24
+
25
+ @classmethod
26
+ def from_names(cls, projection: str, zone: str, units: DistanceUnitsEnum = None) -> 'CrsSpec':
27
+ return cls(None, projection, zone, units)
28
+
29
+ def to_string(self) -> str:
30
+ has_epsg = self.epsg_code is not None
31
+ if has_epsg:
32
+ return 'CRS (EPSG=%s, UNITS=%s)' % (self.epsg_code, self.units)
33
+ else:
34
+ return 'CRS (PROJ=%s, ZONE=%s, UNITS=%s)' % (self.projection, self.zone, self.units)
35
+
36
+
37
+ @dataclass_json(letter_case=LetterCase.PASCAL)
38
+ @dataclass
39
+ class CrsEntry:
40
+ id: str # DotSpatial string for projection
41
+ name: str # DotSpatial string for zone
42
+
43
+
44
+
@@ -0,0 +1,8 @@
1
+ from strenum import StrEnum
2
+
3
+
4
+ class DistanceUnitsEnum(StrEnum):
5
+ Undefined = 'Undefined'
6
+ Meters = 'Meters'
7
+ Feet = 'Feet'
8
+ FeetUS = 'FeetUS'
@@ -0,0 +1,44 @@
1
+ from typing import List, Tuple
2
+ from functools import reduce
3
+ from dataclasses import dataclass
4
+ from dataclasses_json import dataclass_json, LetterCase
5
+ from .GeoLocation import GeoLocation
6
+ from zonevu.zonevu.Services.Error import ZonevuError
7
+
8
+
9
+ @dataclass_json(letter_case=LetterCase.PASCAL)
10
+ @dataclass
11
+ class GeoBox:
12
+ """
13
+ Represents the bounds of a map in geolocations
14
+ """
15
+ lower_left: GeoLocation
16
+ upper_right: GeoLocation
17
+
18
+ @classmethod
19
+ def from_locations(cls, locations: List[GeoLocation]):
20
+ if len(locations) == 0:
21
+ raise ZonevuError.local('cannot create a GeoBox from a zero length list of geolocations')
22
+
23
+ lower_left = reduce(lambda l1, l2: GeoLocation.lower_left_of(l1, l2), locations)
24
+ upper_right = reduce(lambda l1, l2: GeoLocation.upper_right_of(l1, l2), locations)
25
+ g = cls(upper_right, lower_left)
26
+ return g
27
+
28
+ @classmethod
29
+ def from_boxes(cls, b1: 'GeoBox', b2: 'GeoBox') -> 'GeoBox':
30
+ lower_left = GeoLocation.lower_left_of(b1.lower_left, b2.lower_left)
31
+ upper_right = GeoLocation.upper_right_of(b1.upper_right, b2.upper_right)
32
+ return cls(lower_left, upper_right)
33
+
34
+ @classmethod
35
+ def from_box_list(cls, boxes: List['GeoBox']) -> 'GeoBox':
36
+ largest_box = reduce(lambda b1, b2: GeoBox.from_boxes(b1, b2), boxes)
37
+ return largest_box
38
+
39
+ @property
40
+ def tuple(self) -> Tuple[float, float, float, float]:
41
+ geobox_tuple = self.lower_left.tuple + self.upper_right.tuple
42
+ return geobox_tuple
43
+
44
+
@@ -0,0 +1,52 @@
1
+ from dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json, LetterCase
3
+ import math
4
+ from typing import Tuple
5
+
6
+
7
+ @dataclass_json(letter_case=LetterCase.PASCAL)
8
+ @dataclass
9
+ class GeoLocation:
10
+ latitude: float
11
+ longitude: float
12
+
13
+ @property
14
+ def tuple(self) -> Tuple[float, float]:
15
+ return self.longitude, self.latitude
16
+
17
+ @staticmethod
18
+ def error(l1: 'GeoLocation', l2: 'GeoLocation') -> float:
19
+ loc_err_lat = l1.latitude - l2.latitude
20
+ loc_err_lon = l1.longitude - l2.longitude
21
+ e = math.sqrt(math.pow(loc_err_lat, 2) + math.pow(loc_err_lon, 2))
22
+ return e
23
+
24
+ def arc_latitude(self) -> float:
25
+ return self.latitude * math.pi / 180
26
+
27
+ def arc_longitude(self) -> float:
28
+ return self.longitude * math.pi / 180
29
+
30
+ @staticmethod
31
+ def bearing(s: 'GeoLocation', f: 'GeoLocation') -> float:
32
+ latitude1 = s.arc_latitude()
33
+ latitude2 = f.arc_latitude()
34
+ longitudeDifference = f.arc_longitude() - s.arc_longitude()
35
+ y = math.sin(longitudeDifference) * math.cos(latitude2)
36
+ x = math.cos(latitude1) * math.sin(latitude2) - \
37
+ math.sin(latitude1) * math.cos(latitude2) * math.cos(longitudeDifference)
38
+ bearing = (math.atan2(y, x) * 180 / math.pi + 360) % 360
39
+ return bearing
40
+
41
+ @classmethod
42
+ def lower_left_of(cls, l1: 'GeoLocation', l2: 'GeoLocation') -> 'GeoLocation':
43
+ min_latitude = min(l1.latitude, l2.latitude)
44
+ min_longitude = min(l1.longitude, l2.longitude)
45
+ return cls(min_latitude, min_longitude)
46
+
47
+ @classmethod
48
+ def upper_right_of(cls, l1: 'GeoLocation', l2: 'GeoLocation') -> 'GeoLocation':
49
+ max_latitude = max(l1.latitude, l2.latitude)
50
+ max_longitude = max(l1.longitude, l2.longitude)
51
+ return cls(max_latitude, max_longitude)
52
+
@@ -0,0 +1,14 @@
1
+ from dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json, LetterCase
3
+ from .Coordinate import Coordinate
4
+ from .GeoLocation import GeoLocation
5
+ from typing import Optional
6
+
7
+
8
+ @dataclass_json(letter_case=LetterCase.PASCAL)
9
+ @dataclass
10
+ class GridCorner:
11
+ inline: int
12
+ crossline: int
13
+ p: Coordinate
14
+ lat_long: Optional[GeoLocation] = None
@@ -0,0 +1,91 @@
1
+ from typing import Optional
2
+ from dataclasses import dataclass
3
+ from dataclasses_json import dataclass_json, LetterCase
4
+ from .GridCorner import GridCorner
5
+ from .Crs import CrsSpec
6
+ from ..Geomodels.SimpleGrid import SimpleGrid
7
+ from .Coordinate import Coordinate
8
+ import math
9
+
10
+
11
+ @dataclass
12
+ class GridAxisInfo:
13
+ start: int
14
+ stop: int
15
+ count: int
16
+
17
+
18
+ @dataclass
19
+ class GridInfo:
20
+ inline_range: GridAxisInfo
21
+ crossline_range: GridAxisInfo
22
+
23
+ @property
24
+ def num_samples(self) -> int:
25
+ return self.inline_range.count * self.crossline_range.count
26
+
27
+
28
+ @dataclass_json(letter_case=LetterCase.PASCAL)
29
+ @dataclass
30
+ class GridGeometry:
31
+ corner1: GridCorner
32
+ corner2: GridCorner
33
+ corner3: GridCorner
34
+ corner4: GridCorner
35
+ coordinate_system: CrsSpec
36
+ inclination: Optional[float] = None
37
+ geo_inclination: Optional[float] = None
38
+ inline_bin_interval: Optional[float] = None
39
+ crossline_bin_interval: Optional[float] = None
40
+ area: Optional[float] = None
41
+
42
+ @property
43
+ def grid_info(self) -> GridInfo:
44
+ c1 = self.corner1
45
+ c3 = self.corner3
46
+ inline_info = GridAxisInfo(c1.inline, c3.inline, c3.inline - c1.inline + 1)
47
+ crossline_info = GridAxisInfo(c1.crossline, c3.crossline, c3.crossline - c1.crossline + 1)
48
+ return GridInfo(inline_info, crossline_info)
49
+
50
+ @classmethod
51
+ def from_simple_grid(cls, grid: SimpleGrid) -> 'GridGeometry':
52
+ """
53
+ Method to set up a simple grid geometry.
54
+ For inclination = 0, rows are west to east, and columns south to north
55
+ Must provide origin, dx, and dy in distance units of provided CRS
56
+ @param grid: a simple grid definition
57
+ @return: a partially filled GridGeometry, where geolocations and geo-inclination not populated.
58
+
59
+ NOTES:
60
+ We set up here a CW grid geometry, where rows (inlines) run from East to West, and columns (crosslines)
61
+ run South to North.
62
+ """
63
+
64
+ radians = math.radians(grid.inclination)
65
+ x_length = grid.dx * grid.num_cols
66
+ y_length = grid.dy * grid.num_rows
67
+ area = x_length * y_length
68
+ if grid.crs.units.lower() == 'meters':
69
+ area = area / 1000000
70
+ else:
71
+ area = area / 27878400
72
+
73
+ c1 = GridCorner(1, 1, grid.origin, None) # LL Un-rotated case
74
+
75
+ c2_offset = Coordinate(x_length, 0)
76
+ c2_point = c2_offset.rotate(radians) + grid.origin
77
+ c2 = GridCorner(grid.num_cols, 1, c2_point, None) # LR Un-rotated case
78
+
79
+ c3_offset = Coordinate(x_length, y_length)
80
+ c3_point = c3_offset.rotate(radians) + grid.origin
81
+ c3 = GridCorner(grid.num_cols, grid.num_rows, c3_point, None) # UR Un-rotated case
82
+
83
+ c4_offset = Coordinate(0, y_length)
84
+ c4_point = c4_offset.rotate(radians) + grid.origin
85
+ c4 = GridCorner(1, grid.num_rows, c4_point, None) # UL Un-rotated case
86
+
87
+ g = cls(c1, c2, c3, c4, grid.crs, grid.inclination, None, grid.dy, grid.dx, area)
88
+ return g
89
+
90
+
91
+
File without changes
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional
3
+ from dataclasses_json import dataclass_json, LetterCase, config
4
+
5
+
6
+ @dataclass_json(letter_case=LetterCase.PASCAL)
7
+ @dataclass
8
+ class Conditioning:
9
+ """
10
+ Represents a ZoneVu geosteering curve conditioning parameter set
11
+ """
12
+ # Amplitude Range filter
13
+ AmplClip: bool = False
14
+ AmplClipRangeMin: Optional[float] = None
15
+ AmplClipRangeMax: Optional[float] = None
16
+ AmplClipInclusiveNotExclusive: Optional[bool] = None
17
+
18
+ # MD Range filter
19
+ MDClip: bool = False
20
+ MDClipRangeMin: Optional[float] = None
21
+ MDClipRangeMax: Optional[float] = None
22
+ MDClipInclusiveNotExclusive: Optional[bool] = None
23
+
24
+ # Despiking filter.
25
+ Despike: bool = False
26
+ VarianceThreshold: Optional[
27
+ float] = None # Absolute variance that is acceptable as a number in the units of the curve data.
28
+ DespikeLen: Optional[int] = None # Should be an odd number. Number of pts in despiking filter.
29
+
30
+ # Interpolation filter.
31
+ Interpolate: bool = False
32
+ MaxGap: Optional[int] = None
33
+
34
+ # SmoothingFilter filter.
35
+ Smooth: bool = False
36
+ SmoothingLen: Optional[int] = None # Number of points in smoothing filter.
37
+
38
+ # Amplitude normalization filter.
39
+ Normalize: bool = False
40
+ Bias: Optional[float] = None # Amplitude shift
41
+ Scalar: Optional[float] = None # Amplitude multiplier
42
+