orchid-python-api 5.25.2__py3-none-any.whl → 5.25.4__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.
- orchid_python_api/examples/search_data_frames.py +1 -1
- {orchid_python_api-5.25.2.dist-info → orchid_python_api-5.25.4.dist-info}/METADATA +4 -3
- orchid_python_api-5.25.4.dist-info/RECORD +38 -0
- {orchid_python_api-5.25.2.dist-info → orchid_python_api-5.25.4.dist-info}/WHEEL +1 -1
- ReleaseNotes.md +0 -708
- copy_orchid_examples.py +0 -88
- copy_orchid_low_level_examples.py +0 -93
- copy_orchid_manual_examples.py +0 -93
- copy_orchid_tutorials.py +0 -88
- orchid/VERSION +0 -1
- orchid/__init__.py +0 -42
- orchid/__version__.py +0 -18
- orchid/base.py +0 -31
- orchid/base_time_series_adapter.py +0 -91
- orchid/configuration.py +0 -162
- orchid/convert.py +0 -44
- orchid/core.py +0 -149
- orchid/dom_project_object.py +0 -28
- orchid/dot_net.py +0 -68
- orchid/dot_net_disposable.py +0 -64
- orchid/dot_net_dom_access.py +0 -241
- orchid/measurement.py +0 -35
- orchid/native_data_frame_adapter.py +0 -247
- orchid/native_fiber_data.py +0 -73
- orchid/native_fiber_data_set_info.py +0 -28
- orchid/native_monitor_adapter.py +0 -67
- orchid/native_project_user_data_adapter.py +0 -137
- orchid/native_stage_adapter.py +0 -631
- orchid/native_stage_part_adapter.py +0 -50
- orchid/native_subsurface_point.py +0 -70
- orchid/native_time_series_adapter.py +0 -54
- orchid/native_trajectory_adapter.py +0 -246
- orchid/native_treatment_calculations.py +0 -158
- orchid/native_treatment_curve_adapter.py +0 -60
- orchid/native_well_adapter.py +0 -134
- orchid/net_date_time.py +0 -328
- orchid/net_enumerable.py +0 -72
- orchid/net_fracture_diagnostics_factory.py +0 -55
- orchid/net_quantity.py +0 -620
- orchid/net_stage_qc.py +0 -62
- orchid/physical_quantity.py +0 -37
- orchid/project.py +0 -182
- orchid/project_store.py +0 -269
- orchid/reference_origins.py +0 -34
- orchid/script_adapter_context.py +0 -81
- orchid/searchable_data_frames.py +0 -44
- orchid/searchable_project_objects.py +0 -190
- orchid/searchable_stage_parts.py +0 -73
- orchid/searchable_stages.py +0 -29
- orchid/unit_system.py +0 -173
- orchid/utils.py +0 -14
- orchid/validation.py +0 -52
- orchid/version.py +0 -37
- orchid_python_api-5.25.2.dist-info/LICENSE +0 -176
- orchid_python_api-5.25.2.dist-info/RECORD +0 -88
- {orchid_python_api-5.25.2.dist-info → orchid_python_api-5.25.4.dist-info}/entry_points.txt +0 -0
- /LICENSE → /orchid_python_api-5.25.4.dist-info/licenses/LICENSE +0 -0
orchid/native_stage_adapter.py
DELETED
|
@@ -1,631 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2017-2025 KAPPA
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
# This file is part of Orchid and related technologies.
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import dataclasses as dc
|
|
20
|
-
import enum
|
|
21
|
-
import math
|
|
22
|
-
from typing import Optional, Tuple, Union
|
|
23
|
-
|
|
24
|
-
import deal
|
|
25
|
-
import option
|
|
26
|
-
import pendulum as pdt
|
|
27
|
-
import toolz.curried as toolz
|
|
28
|
-
|
|
29
|
-
import orchid.base
|
|
30
|
-
from orchid import (
|
|
31
|
-
dot_net_disposable as dnd,
|
|
32
|
-
dot_net_dom_access as dna,
|
|
33
|
-
dom_project_object as dpo,
|
|
34
|
-
measurement as om,
|
|
35
|
-
native_stage_part_adapter as spa,
|
|
36
|
-
native_subsurface_point as nsp,
|
|
37
|
-
native_treatment_curve_adapter as ntc,
|
|
38
|
-
net_date_time as ndt,
|
|
39
|
-
net_fracture_diagnostics_factory as fdf,
|
|
40
|
-
net_quantity as onq,
|
|
41
|
-
reference_origins as origins,
|
|
42
|
-
searchable_stage_parts as ssp,
|
|
43
|
-
unit_system as units,
|
|
44
|
-
validation
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
|
48
|
-
from Orchid.FractureDiagnostics import FormationConnectionType, IStagePart
|
|
49
|
-
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
|
50
|
-
from Orchid.FractureDiagnostics.Factories import Calculations
|
|
51
|
-
# noinspection PyUnresolvedReferences
|
|
52
|
-
from Orchid.FractureDiagnostics.SDKFacade import ScriptAdapter
|
|
53
|
-
# noinspection PyUnresolvedReferences
|
|
54
|
-
import UnitsNet
|
|
55
|
-
# noinspection PyUnresolvedReferences
|
|
56
|
-
from System.Collections.Generic import List
|
|
57
|
-
# noinspection PyUnresolvedReferences
|
|
58
|
-
import System
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
VALID_LENGTH_UNIT_MESSAGE = 'The parameter, `in_length_unit`, must be a unit system length.'
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
_object_factory = fdf.create()
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# TODO: Consider adding base with methods like `toNetEnum` and `fromNetEnum`
|
|
68
|
-
class ConnectionType(enum.Enum):
|
|
69
|
-
PLUG_AND_PERF = FormationConnectionType.PlugAndPerf
|
|
70
|
-
SLIDING_SLEEVE = FormationConnectionType.SlidingSleeve
|
|
71
|
-
SINGLE_POINT_ENTRY = FormationConnectionType.SinglePointEntry
|
|
72
|
-
OPEN_HOLE = FormationConnectionType.OpenHole
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def as_connection_type(type_value):
|
|
76
|
-
@toolz.curry
|
|
77
|
-
def has_value(value, enum_type):
|
|
78
|
-
return value == enum_type.value
|
|
79
|
-
|
|
80
|
-
return toolz.pipe(iter(ConnectionType),
|
|
81
|
-
toolz.filter(has_value(type_value)),
|
|
82
|
-
toolz.nth(0))
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# This pre-condition applies to the public methods:
|
|
86
|
-
# - bottom_location
|
|
87
|
-
# - center_location
|
|
88
|
-
# - cluster_location
|
|
89
|
-
# - top_location
|
|
90
|
-
# but is implemented here to ensure common behavior among all these public methods.
|
|
91
|
-
@deal.pre(lambda _depth_datum, _reference_frame, in_length_unit, _net_subsurface_point_func:
|
|
92
|
-
validation.is_unit_system_length(in_length_unit),
|
|
93
|
-
message=VALID_LENGTH_UNIT_MESSAGE)
|
|
94
|
-
def subsurface_point_in_length_unit(depth_datum: origins.DepthDatum,
|
|
95
|
-
xy_reference_frame: origins.WellReferenceFrameXy,
|
|
96
|
-
in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
97
|
-
net_subsurface_point_func) -> nsp.SubsurfacePoint:
|
|
98
|
-
"""
|
|
99
|
-
Calculate the subsurface point `in_length_unit` whose value is calculated by the
|
|
100
|
-
callable, `net_subsurface_point_func`.
|
|
101
|
-
|
|
102
|
-
Although this method is public, the author intends it to be "private." The author has made it public
|
|
103
|
-
**only** to support unit testing. No other usage is supported.
|
|
104
|
-
|
|
105
|
-
Args:
|
|
106
|
-
depth_datum: The datum from which we measure depths.
|
|
107
|
-
xy_reference_frame: The reference frame for easting-northing coordinates.
|
|
108
|
-
in_length_unit: The unit of length available from the returned value.
|
|
109
|
-
net_subsurface_point_func: The callable to calculate the subsurface point in .NET.
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
The subsurface point in the requested unit of length.
|
|
113
|
-
"""
|
|
114
|
-
net_subsurface_point = net_subsurface_point_func(xy_reference_frame.value, depth_datum.value)
|
|
115
|
-
result = nsp.SubsurfacePoint(net_subsurface_point, in_length_unit)
|
|
116
|
-
return result
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
class NativeStageAdapter(dpo.DomProjectObject):
|
|
120
|
-
"""Adapts a .NET IStage to be more Pythonic."""
|
|
121
|
-
|
|
122
|
-
def __init__(self, adaptee, calculations_factory=None):
|
|
123
|
-
super().__init__(adaptee, orchid.base.constantly(adaptee.Well.Project))
|
|
124
|
-
self.calculations_factory = Calculations.FractureDiagnosticsCalculationsFactory() \
|
|
125
|
-
if not calculations_factory else calculations_factory
|
|
126
|
-
|
|
127
|
-
cluster_count = dna.dom_property('number_of_clusters', 'The number of clusters for this stage')
|
|
128
|
-
display_name_with_well = dna.dom_property('display_name_with_well',
|
|
129
|
-
'The display stage number including the well name')
|
|
130
|
-
display_name_without_well = dna.dom_property('display_name_without_well',
|
|
131
|
-
'The display stage number excluding the well name')
|
|
132
|
-
display_stage_number = dna.dom_property('display_stage_number', 'The display stage number for the stage')
|
|
133
|
-
global_stage_sequence_number = dna.dom_property('global_stage_sequence_number',
|
|
134
|
-
'The global sequence number of this stage')
|
|
135
|
-
order_of_completion_on_well = dna.dom_property('order_of_completion_on_well',
|
|
136
|
-
'The order in which this stage was completed on its well')
|
|
137
|
-
stage_type = dna.transformed_dom_property('stage_type', 'The formation connection type of this stage',
|
|
138
|
-
as_connection_type)
|
|
139
|
-
start_time = dna.transformed_dom_property('start_time', 'The start time of the stage treatment',
|
|
140
|
-
ndt.as_date_time)
|
|
141
|
-
stop_time = dna.transformed_dom_property('stop_time', 'The stop time of the stage treatment',
|
|
142
|
-
ndt.as_date_time)
|
|
143
|
-
|
|
144
|
-
def _get_time_range(self) -> pdt.Interval:
|
|
145
|
-
return pdt.Interval(self.start_time, self.stop_time)
|
|
146
|
-
|
|
147
|
-
def _set_time_range(self, to_time_range: pdt.Interval):
|
|
148
|
-
to_start_net_time = ndt.as_net_date_time(to_time_range.start)
|
|
149
|
-
to_stop_net_time = ndt.as_net_date_time(to_time_range.end)
|
|
150
|
-
if len(self.stage_parts()) == 1:
|
|
151
|
-
single_stage_part = toolz.first(self.stage_parts())
|
|
152
|
-
with dnd.disposable(single_stage_part.dom_object.ToMutable()) as mutable_first_stage_part:
|
|
153
|
-
mutable_first_stage_part.SetStartStopTimes(to_start_net_time,
|
|
154
|
-
to_stop_net_time)
|
|
155
|
-
elif len(self.stage_parts()) > 1:
|
|
156
|
-
single_stage_part = toolz.first(self.stage_parts())
|
|
157
|
-
with dnd.disposable(single_stage_part.dom_object.ToMutable()) as mutable_first_stage_part:
|
|
158
|
-
mutable_first_stage_part.SetStartStopTimes(to_start_net_time,
|
|
159
|
-
single_stage_part.dom_object.StopTime)
|
|
160
|
-
last_stage_part = toolz.last(self.stage_parts())
|
|
161
|
-
with dnd.disposable(last_stage_part.dom_object.ToMutable()) as mutable_last_stage_part:
|
|
162
|
-
mutable_last_stage_part.SetStartStopTimes(last_stage_part.dom_object.StartTime,
|
|
163
|
-
to_stop_net_time)
|
|
164
|
-
else: # No stage parts
|
|
165
|
-
factory = fdf.create()
|
|
166
|
-
stage_part_to_add = factory.CreateStagePart(self.dom_object, to_start_net_time,
|
|
167
|
-
to_stop_net_time, None)
|
|
168
|
-
with dnd.disposable(self.dom_object.ToMutable()) as mutable_stage:
|
|
169
|
-
mutable_stage.Parts.Add(stage_part_to_add)
|
|
170
|
-
|
|
171
|
-
time_range = property(fget=_get_time_range, fset=_set_time_range,
|
|
172
|
-
doc='The time range (start and end) of this stage')
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def isip(self) -> om.Quantity:
|
|
176
|
-
"""
|
|
177
|
-
Return the instantaneous shut in pressure of this stage in project units.
|
|
178
|
-
"""
|
|
179
|
-
return onq.as_measurement_from_option(self.expect_project_units.PRESSURE, self.dom_object.Isip)
|
|
180
|
-
|
|
181
|
-
@property
|
|
182
|
-
def pnet(self) -> om.Quantity:
|
|
183
|
-
"""
|
|
184
|
-
Return the net pressure of this stage in project units.
|
|
185
|
-
|
|
186
|
-
The net pressure of a stage is calculated by the formula:
|
|
187
|
-
pnet = isip + fluid-density * tvd - shmin (where tvd is the true vertical depth)
|
|
188
|
-
"""
|
|
189
|
-
return onq.as_measurement_from_option(self.expect_project_units.PRESSURE, self.dom_object.Pnet)
|
|
190
|
-
|
|
191
|
-
@property
|
|
192
|
-
def shmin(self) -> om.Quantity:
|
|
193
|
-
"""
|
|
194
|
-
Return the minimum horizontal stress of this stage in project units.
|
|
195
|
-
"""
|
|
196
|
-
|
|
197
|
-
return onq.as_measurement_from_option(self.expect_project_units.PRESSURE, self.dom_object.Shmin)
|
|
198
|
-
|
|
199
|
-
@staticmethod
|
|
200
|
-
def _sampled_quantity_name_curve_map(sampled_quantity_name):
|
|
201
|
-
candidates = toolz.pipe(ntc.TreatmentCurveTypes,
|
|
202
|
-
toolz.filter(lambda e: e.value == sampled_quantity_name),
|
|
203
|
-
list)
|
|
204
|
-
if len(candidates) == 0:
|
|
205
|
-
raise KeyError(f'Unknown sampled quantity name: "{sampled_quantity_name}"')
|
|
206
|
-
|
|
207
|
-
assert len(candidates) == 1, f'Sampled quantity name "{sampled_quantity_name}"' \
|
|
208
|
-
f' selects many curve types: {candidates}'
|
|
209
|
-
|
|
210
|
-
return candidates[0]
|
|
211
|
-
|
|
212
|
-
def _center_location_depth(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
213
|
-
depth_datum: origins.DepthDatum) -> om.Quantity:
|
|
214
|
-
"""
|
|
215
|
-
Return the depth of the stage center relative to the specified `depth_datum.`
|
|
216
|
-
|
|
217
|
-
Args:
|
|
218
|
-
in_length_unit: The unit of length for the returned Measurement.
|
|
219
|
-
depth_datum: The reference datum for the depth.
|
|
220
|
-
"""
|
|
221
|
-
subsurface_point = self.center_location(in_length_unit, origins.WellReferenceFrameXy.ABSOLUTE_STATE_PLANE,
|
|
222
|
-
depth_datum)
|
|
223
|
-
return subsurface_point.depth
|
|
224
|
-
|
|
225
|
-
def bottom_location(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
226
|
-
xy_reference_frame: origins.WellReferenceFrameXy,
|
|
227
|
-
depth_datum: origins.DepthDatum) -> nsp.SubsurfacePoint:
|
|
228
|
-
"""
|
|
229
|
-
Return the location of the bottom of this stage in the `xy_well_reference_frame` using the
|
|
230
|
-
`depth_datum` in the specified unit.
|
|
231
|
-
|
|
232
|
-
Args:
|
|
233
|
-
in_length_unit: The unit of length available from the returned value.
|
|
234
|
-
xy_reference_frame: The reference frame for easting-northing coordinates.
|
|
235
|
-
depth_datum: The datum from which we measure depths.
|
|
236
|
-
|
|
237
|
-
Returns:
|
|
238
|
-
The `SubsurfacePoint` of the stage bottom.
|
|
239
|
-
"""
|
|
240
|
-
|
|
241
|
-
return subsurface_point_in_length_unit(depth_datum, xy_reference_frame, in_length_unit,
|
|
242
|
-
self.dom_object.GetStageLocationBottom)
|
|
243
|
-
|
|
244
|
-
def center_location(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
245
|
-
xy_reference_frame: origins.WellReferenceFrameXy,
|
|
246
|
-
depth_datum: origins.DepthDatum) -> nsp.SubsurfacePoint:
|
|
247
|
-
"""
|
|
248
|
-
Return the location of the center of this stage in the `xy_well_reference_frame` using the `depth_datum`
|
|
249
|
-
in the specified unit.
|
|
250
|
-
|
|
251
|
-
Args:
|
|
252
|
-
in_length_unit: The unit of length available from the returned value.
|
|
253
|
-
xy_reference_frame: The reference frame for easting-northing coordinates.
|
|
254
|
-
depth_datum: The datum from which we measure depths.
|
|
255
|
-
|
|
256
|
-
Returns:
|
|
257
|
-
The `SubsurfacePoint` of the stage center.
|
|
258
|
-
"""
|
|
259
|
-
return subsurface_point_in_length_unit(depth_datum, xy_reference_frame, in_length_unit,
|
|
260
|
-
self.dom_object.GetStageLocationCenter)
|
|
261
|
-
|
|
262
|
-
def center_location_easting(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
263
|
-
xy_well_reference_frame: origins.WellReferenceFrameXy) -> om.Quantity:
|
|
264
|
-
"""
|
|
265
|
-
Return the easting location of the stage center relative to the specified reference frame in the
|
|
266
|
-
specified unit.
|
|
267
|
-
|
|
268
|
-
Args:
|
|
269
|
-
in_length_unit: An unit of the unit of length for the returned Measurement.
|
|
270
|
-
xy_well_reference_frame: The reference frame defining the origin.
|
|
271
|
-
|
|
272
|
-
Returns:
|
|
273
|
-
A measurement.
|
|
274
|
-
"""
|
|
275
|
-
result = self.center_location(in_length_unit, xy_well_reference_frame, origins.DepthDatum.KELLY_BUSHING).x
|
|
276
|
-
return result
|
|
277
|
-
|
|
278
|
-
def center_location_northing(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
279
|
-
xy_well_reference_frame: origins.WellReferenceFrameXy) -> om.Quantity:
|
|
280
|
-
"""
|
|
281
|
-
Return the northing location of the stage center in the `xy_well_reference_frame` in the specified unit.
|
|
282
|
-
|
|
283
|
-
Args:
|
|
284
|
-
in_length_unit: The requested resultant length unit.
|
|
285
|
-
xy_well_reference_frame: The reference frame defining the origin.
|
|
286
|
-
|
|
287
|
-
Returns:
|
|
288
|
-
A measurement.
|
|
289
|
-
"""
|
|
290
|
-
subsurface_point = self.center_location(in_length_unit, xy_well_reference_frame,
|
|
291
|
-
origins.DepthDatum.KELLY_BUSHING)
|
|
292
|
-
return subsurface_point.y
|
|
293
|
-
|
|
294
|
-
def center_location_mdkb(self, in_length_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
295
|
-
"""
|
|
296
|
-
Return the measured depth of the stage center in project units.
|
|
297
|
-
|
|
298
|
-
Args:
|
|
299
|
-
in_length_unit: The unit of length for the returned Measurement.
|
|
300
|
-
"""
|
|
301
|
-
return (self.md_top(in_length_unit) + self.md_bottom(in_length_unit)) / 2
|
|
302
|
-
|
|
303
|
-
def center_location_tvdgl(self, in_length_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
304
|
-
"""
|
|
305
|
-
Returns the total vertical depth from ground level of the stage center in project units.
|
|
306
|
-
|
|
307
|
-
Args:
|
|
308
|
-
in_length_unit: The unit of length for the returned Measurement.
|
|
309
|
-
"""
|
|
310
|
-
return self._center_location_depth(in_length_unit, origins.DepthDatum.GROUND_LEVEL)
|
|
311
|
-
|
|
312
|
-
def center_location_tvdss(self, in_length_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
313
|
-
"""
|
|
314
|
-
Returns the total vertical depth from sea level of the stage center in project units.
|
|
315
|
-
|
|
316
|
-
Args:
|
|
317
|
-
in_length_unit: The unit of length for the returned Measurement.
|
|
318
|
-
"""
|
|
319
|
-
return self._center_location_depth(in_length_unit, origins.DepthDatum.SEA_LEVEL)
|
|
320
|
-
|
|
321
|
-
def center_location_xy(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
322
|
-
xy_well_reference_frame: origins.WellReferenceFrameXy) -> Tuple[om.Quantity,
|
|
323
|
-
om.Quantity]:
|
|
324
|
-
"""
|
|
325
|
-
Return the easting-northing location of the stage center in the `xy_well_reference_frame` in project units.
|
|
326
|
-
|
|
327
|
-
Args:
|
|
328
|
-
in_length_unit: The unit of length for the returned Measurement.
|
|
329
|
-
xy_well_reference_frame: The reference frame defining the origin.
|
|
330
|
-
|
|
331
|
-
Returns:
|
|
332
|
-
A tuple
|
|
333
|
-
"""
|
|
334
|
-
subsurface_point = self.center_location(in_length_unit, xy_well_reference_frame,
|
|
335
|
-
origins.DepthDatum.KELLY_BUSHING)
|
|
336
|
-
return subsurface_point.x, subsurface_point.y
|
|
337
|
-
|
|
338
|
-
@deal.pre(lambda _self, _in_length_unit, cluster_no, _xy_reference_frame, _depth_datum: cluster_no >= 0)
|
|
339
|
-
def cluster_location(self, in_length_unit: Union[units.UsOilfield, units.Metric], cluster_no: int,
|
|
340
|
-
xy_reference_frame: origins.WellReferenceFrameXy,
|
|
341
|
-
depth_datum: origins.DepthDatum) -> nsp.SubsurfacePoint:
|
|
342
|
-
"""
|
|
343
|
-
Return the location of the bottom of this stage in the `xy_well_reference_frame` using the
|
|
344
|
-
`depth_datum` in the specified unit.
|
|
345
|
-
|
|
346
|
-
Args:
|
|
347
|
-
in_length_unit: The unit of length available from the returned value.
|
|
348
|
-
cluster_no: The number identifying the cluster whose location is sought.
|
|
349
|
-
xy_reference_frame: The reference frame for easting-northing coordinates.
|
|
350
|
-
depth_datum: The datum from which we measure depths.
|
|
351
|
-
|
|
352
|
-
Returns:
|
|
353
|
-
The `SubsurfacePoint` of the stage cluster identified by `cluster_no`.
|
|
354
|
-
"""
|
|
355
|
-
stage_location_cluster_func = toolz.curry(self.dom_object.GetStageLocationCluster, cluster_no)
|
|
356
|
-
return subsurface_point_in_length_unit(depth_datum, xy_reference_frame, in_length_unit,
|
|
357
|
-
stage_location_cluster_func)
|
|
358
|
-
|
|
359
|
-
@deal.pre(validation.arg_is_acceptable_pressure_unit)
|
|
360
|
-
def isip_in_pressure_unit(self, target_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
361
|
-
return onq.as_measurement_from_option(target_unit, self.dom_object.Isip)
|
|
362
|
-
|
|
363
|
-
def md_bottom(self, in_length_unit: Union[units.UsOilfield, units.Metric]):
|
|
364
|
-
"""
|
|
365
|
-
Return the measured depth of the bottom of this stage (farthest from the wellhead / closest to the toe)
|
|
366
|
-
in the specified unit.
|
|
367
|
-
|
|
368
|
-
Args:
|
|
369
|
-
in_length_unit: An unit of the unit of length for the returned Measurement.
|
|
370
|
-
|
|
371
|
-
Returns:
|
|
372
|
-
The measured depth of the stage bottom in the specified unit.
|
|
373
|
-
"""
|
|
374
|
-
return onq.as_measurement(in_length_unit, option.maybe(self.dom_object.MdBottom))
|
|
375
|
-
|
|
376
|
-
def md_top(self, in_length_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
377
|
-
"""
|
|
378
|
-
Return the measured depth of the top of this stage (closest to the wellhead / farthest from the toe)
|
|
379
|
-
in the specified unit.
|
|
380
|
-
|
|
381
|
-
Args:
|
|
382
|
-
in_length_unit: An unit of the requested resultant length unit.
|
|
383
|
-
|
|
384
|
-
Returns;
|
|
385
|
-
The measured depth of the stage top in the specified unit.
|
|
386
|
-
"""
|
|
387
|
-
return onq.as_measurement(in_length_unit, option.maybe(self.dom_object.MdTop))
|
|
388
|
-
|
|
389
|
-
@deal.pre(validation.arg_is_acceptable_pressure_unit)
|
|
390
|
-
def pnet_in_pressure_unit(self, target_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
391
|
-
return onq.as_measurement_from_option(target_unit, self.dom_object.Pnet)
|
|
392
|
-
|
|
393
|
-
@deal.pre(validation.arg_is_acceptable_pressure_unit)
|
|
394
|
-
def shmin_in_pressure_unit(self, target_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
395
|
-
return onq.as_measurement_from_option(target_unit, self.dom_object.Shmin)
|
|
396
|
-
|
|
397
|
-
def stage_length(self, in_length_unit: Union[units.UsOilfield, units.Metric]) -> om.Quantity:
|
|
398
|
-
"""
|
|
399
|
-
Return the stage length in the specified unit.
|
|
400
|
-
|
|
401
|
-
Args:
|
|
402
|
-
in_length_unit: An unit of the unit of length for the returned Measurement.
|
|
403
|
-
|
|
404
|
-
Returns:
|
|
405
|
-
The Measurement of the length of this stage.
|
|
406
|
-
"""
|
|
407
|
-
return self.md_bottom(in_length_unit) - self.md_top(in_length_unit)
|
|
408
|
-
|
|
409
|
-
def stage_parts(self) -> ssp.SearchableStageParts:
|
|
410
|
-
"""
|
|
411
|
-
Return a `ssp.SearchableStageParts` for all the stage parts for this stage.
|
|
412
|
-
|
|
413
|
-
Returns:
|
|
414
|
-
An `ssp.SearchableStageParts` for all the stage parts for this stage.
|
|
415
|
-
"""
|
|
416
|
-
return ssp.SearchableStageParts(spa.NativeStagePartAdapter, self.dom_object.Parts)
|
|
417
|
-
|
|
418
|
-
def top_location(self, in_length_unit: Union[units.UsOilfield, units.Metric],
|
|
419
|
-
xy_reference_frame: origins.WellReferenceFrameXy,
|
|
420
|
-
depth_datum: origins.DepthDatum) -> nsp.SubsurfacePoint:
|
|
421
|
-
"""
|
|
422
|
-
Return the location of the top of this stage in the `xy_well_reference_frame` using the `depth_datum`
|
|
423
|
-
in the specified unit.
|
|
424
|
-
|
|
425
|
-
Args:
|
|
426
|
-
in_length_unit: The unit of length available from the returned value.
|
|
427
|
-
xy_reference_frame: The reference frame for easting-northing coordinates.
|
|
428
|
-
depth_datum: The datum from which we measure depths.
|
|
429
|
-
|
|
430
|
-
Returns:
|
|
431
|
-
The `SubsurfacePoint` of the stage top.
|
|
432
|
-
"""
|
|
433
|
-
return subsurface_point_in_length_unit(depth_datum, xy_reference_frame, in_length_unit,
|
|
434
|
-
self.dom_object.GetStageLocationTop)
|
|
435
|
-
|
|
436
|
-
def treatment_curves(self):
|
|
437
|
-
"""
|
|
438
|
-
Returns the dictionary of treatment curves for this treatment_stage.
|
|
439
|
-
|
|
440
|
-
Request a specific curve from the dictionary using the constants defined in `orchid`:
|
|
441
|
-
|
|
442
|
-
- `PROPPANT_CONCENTRATION`
|
|
443
|
-
- `SLURRY_RATE`
|
|
444
|
-
- `TREATING_PRESSURE`
|
|
445
|
-
|
|
446
|
-
Returns:
|
|
447
|
-
The dictionary containing the available treatment curves.
|
|
448
|
-
"""
|
|
449
|
-
if not self.dom_object.TreatmentCurves.Items:
|
|
450
|
-
return {}
|
|
451
|
-
|
|
452
|
-
def add_curve(so_far, treatment_curve):
|
|
453
|
-
curve_name = self._sampled_quantity_name_curve_map(treatment_curve.sampled_quantity_name)
|
|
454
|
-
treatment_curve_map = {curve_name: treatment_curve}
|
|
455
|
-
return toolz.merge(treatment_curve_map, so_far)
|
|
456
|
-
|
|
457
|
-
result = toolz.pipe(self.dom_object.TreatmentCurves.Items, # start with .NET treatment curves
|
|
458
|
-
toolz.map(ntc.NativeTreatmentCurveAdapter), # wrap them in a facade
|
|
459
|
-
# Transform the map to a dictionary keyed by the sampled quantity name
|
|
460
|
-
lambda cs: toolz.reduce(add_curve, cs, {}))
|
|
461
|
-
return result
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
@dc.dataclass
|
|
465
|
-
class CreateStageDto:
|
|
466
|
-
"""
|
|
467
|
-
A data-transfer object (DTO) containing the required and optional data used to create new stages.
|
|
468
|
-
|
|
469
|
-
This class enforces a number of constraints on the data needed to create a stage. Consider viewing the source
|
|
470
|
-
code of the class to understand those constraints. (The class will throw exceptions if the constraints are not met
|
|
471
|
-
at run-time.)
|
|
472
|
-
|
|
473
|
-
Additionally, the comments of this class contain a number of "warnings" for situations where data is not required,
|
|
474
|
-
but the consequences for **not** supplying the data may not be desirable or may not be expected.
|
|
475
|
-
"""
|
|
476
|
-
stage_no: int # Must be positive
|
|
477
|
-
connection_type: ConnectionType
|
|
478
|
-
md_top: om.Quantity # Must be length
|
|
479
|
-
md_bottom: om.Quantity # Must be length
|
|
480
|
-
|
|
481
|
-
cluster_count: int = 0 # Must be non-negative
|
|
482
|
-
maybe_shmin: Optional[om.Quantity] = None # If not `None`, must be pressure
|
|
483
|
-
# WARNING: one need supply neither a start time nor a stop time; however, not supplying this data can
|
|
484
|
-
# produce unexpected behavior for the `global_stage_sequence_number` property. For example, one can
|
|
485
|
-
# generate duplicate values for the `global_stage_sequence_number`. This unexpected behavior is a known
|
|
486
|
-
# issue with Orchid.
|
|
487
|
-
#
|
|
488
|
-
# Note supplying no value (an implicit `None`) results in the largest possible .NET time range.
|
|
489
|
-
maybe_time_range: Optional[pdt.Interval] = None
|
|
490
|
-
# WARNING: one must currently supply an ISIP for each stage; otherwise, Orchid fails to correctly load
|
|
491
|
-
# the project saved with the added stages.
|
|
492
|
-
maybe_isip: Optional[om.Quantity] = None # If not `None`, must be a pressure
|
|
493
|
-
|
|
494
|
-
order_of_completion_on_well = property(fget=lambda self: self.stage_no - 1)
|
|
495
|
-
|
|
496
|
-
def __post_init__(self):
|
|
497
|
-
# See the
|
|
498
|
-
# [StackOverflow post](https://stackoverflow.com/questions/54488765/validating-input-when-mutating-a-dataclass)
|
|
499
|
-
if self.stage_no <= 0:
|
|
500
|
-
raise ValueError(f'Expected stage_no to be positive. Found {self.stage_no}')
|
|
501
|
-
if not self.md_top.check('[length]'):
|
|
502
|
-
raise ValueError(f'Expected md_top to be a length. Found {self.md_top:~P}')
|
|
503
|
-
if not self.md_bottom.check('[length]'):
|
|
504
|
-
raise ValueError(f'Expected md_bottom to be a length. Found {self.md_bottom:~P}')
|
|
505
|
-
if self.cluster_count < 0:
|
|
506
|
-
raise ValueError(f'Expected cluster_count to be non-negative. Found {self.cluster_count}')
|
|
507
|
-
if self.maybe_isip is not None:
|
|
508
|
-
if not self.maybe_isip.check('[pressure]'):
|
|
509
|
-
raise ValueError(f'Expected maybe_isip to be a pressure if not None. Found {self.maybe_isip:~P}')
|
|
510
|
-
if self.maybe_shmin is not None:
|
|
511
|
-
if not self.maybe_shmin.check('[pressure]'):
|
|
512
|
-
raise ValueError(f'Expected maybe_shmin to be a pressure if not None. Found {self.maybe_shmin:~P}')
|
|
513
|
-
|
|
514
|
-
def create_stage(self, well) -> NativeStageAdapter:
|
|
515
|
-
"""
|
|
516
|
-
Creates a stage from this DTO.
|
|
517
|
-
|
|
518
|
-
Args:
|
|
519
|
-
well (NativeWellAdapter): The well of the created `NativeStageAdapter`
|
|
520
|
-
|
|
521
|
-
Returns:
|
|
522
|
-
The `NativeStageAdapter` wrapping the created .NET `IStage` instance.
|
|
523
|
-
|
|
524
|
-
"""
|
|
525
|
-
project_unit_system = units.as_unit_system(well.dom_object.Project.ProjectUnits)
|
|
526
|
-
native_md_top = onq.as_net_quantity(project_unit_system.LENGTH, self.md_top)
|
|
527
|
-
native_md_bottom = onq.as_net_quantity(project_unit_system.LENGTH, self.md_bottom)
|
|
528
|
-
if self.maybe_shmin is None:
|
|
529
|
-
native_shmin = ScriptAdapter.MakeOptionNone[UnitsNet.Pressure]()
|
|
530
|
-
elif math.isnan(self.maybe_shmin.magnitude):
|
|
531
|
-
native_shmin = ScriptAdapter.MakeOptionNone[UnitsNet.Pressure]()
|
|
532
|
-
else:
|
|
533
|
-
native_shmin = ScriptAdapter.MakeOptionSome(
|
|
534
|
-
onq.as_net_quantity(project_unit_system.PRESSURE, self.maybe_shmin))
|
|
535
|
-
completion_order_on_well = System.UInt32(self.order_of_completion_on_well)
|
|
536
|
-
connection_type = self.connection_type.value
|
|
537
|
-
cluster_count = System.UInt32(self.cluster_count)
|
|
538
|
-
no_time_range_native_stage = self.create_net_stage(well.dom_object, completion_order_on_well,
|
|
539
|
-
connection_type, native_md_top,
|
|
540
|
-
native_md_bottom, native_shmin,
|
|
541
|
-
cluster_count)
|
|
542
|
-
|
|
543
|
-
with dnd.disposable(no_time_range_native_stage.ToMutable()) as mutable_stage:
|
|
544
|
-
native_start_time = (ndt.as_net_date_time(self.maybe_time_range.start)
|
|
545
|
-
if self.maybe_time_range is not None
|
|
546
|
-
else pdt.DateTime.max)
|
|
547
|
-
native_stop_time = (ndt.as_net_date_time(self.maybe_time_range.end)
|
|
548
|
-
if self.maybe_time_range is not None
|
|
549
|
-
else pdt.DateTime.max)
|
|
550
|
-
if self.maybe_isip is None:
|
|
551
|
-
native_isip = None
|
|
552
|
-
elif math.isnan(self.maybe_isip.magnitude):
|
|
553
|
-
native_isip = None
|
|
554
|
-
else:
|
|
555
|
-
native_isip = onq.as_net_quantity(project_unit_system.PRESSURE, self.maybe_isip)
|
|
556
|
-
|
|
557
|
-
stage_part = self.create_net_stage_part(no_time_range_native_stage, native_start_time, native_stop_time,
|
|
558
|
-
native_isip)
|
|
559
|
-
self.add_stage_part_to_stage(mutable_stage, stage_part)
|
|
560
|
-
|
|
561
|
-
# Alias to better communicate intent
|
|
562
|
-
created_native_stage = no_time_range_native_stage
|
|
563
|
-
return NativeStageAdapter(created_native_stage)
|
|
564
|
-
|
|
565
|
-
@staticmethod
|
|
566
|
-
def create_net_stage(native_well, completion_order_on_well, connection_type, native_md_top, native_md_bottom,
|
|
567
|
-
native_shmin, cluster_count):
|
|
568
|
-
"""
|
|
569
|
-
Create a .NET `IStage`.
|
|
570
|
-
|
|
571
|
-
This method primarily exists so that I can mock the call in unit tests.
|
|
572
|
-
|
|
573
|
-
Args:
|
|
574
|
-
native_well: The .NET `IWell` instance to which the created `IStage` refers.
|
|
575
|
-
completion_order_on_well: The order of completion of this stage of the referenced `IWell`.
|
|
576
|
-
connection_type: The .NET `FormationConnectionType` of the created .NET stage.
|
|
577
|
-
native_md_top: The measured depth of the top (toward the heel) of the created .NET stage.
|
|
578
|
-
native_md_bottom: The measured depth of the bottom (toward the toe) of the created .NET stage.
|
|
579
|
-
native_shmin: The minimum horizontal stress of the created .NET stage.
|
|
580
|
-
cluster_count: The cluster count of the created .NET stage.
|
|
581
|
-
|
|
582
|
-
Returns:
|
|
583
|
-
The newly created .NET `IStage` instance.
|
|
584
|
-
"""
|
|
585
|
-
no_time_range_native_stage = _object_factory.CreateStage(
|
|
586
|
-
System.UInt32(completion_order_on_well),
|
|
587
|
-
native_well,
|
|
588
|
-
connection_type,
|
|
589
|
-
native_md_top,
|
|
590
|
-
native_md_bottom,
|
|
591
|
-
native_shmin,
|
|
592
|
-
System.UInt32(cluster_count)
|
|
593
|
-
)
|
|
594
|
-
return no_time_range_native_stage
|
|
595
|
-
|
|
596
|
-
@staticmethod
|
|
597
|
-
def create_net_stage_part(native_stage, native_start_time, native_stop_time, native_isip):
|
|
598
|
-
"""
|
|
599
|
-
Create . .NET `IStagePart` instance.
|
|
600
|
-
|
|
601
|
-
This method primarily exists so that I can mock the call in unit tests.
|
|
602
|
-
|
|
603
|
-
Args:
|
|
604
|
-
native_stage: The .NET `IStage` to which the created `IStagePart` refers.
|
|
605
|
-
native_start_time: The start time of the created `IStagePart`.
|
|
606
|
-
native_stop_time: The stop time of the created `IStagePart`.
|
|
607
|
-
native_isip: The ISIP of the created `IStagePart`.
|
|
608
|
-
|
|
609
|
-
Returns:
|
|
610
|
-
The newly created `IStagePart` with the specified details.
|
|
611
|
-
"""
|
|
612
|
-
stage_part = _object_factory.CreateStagePart(native_stage,
|
|
613
|
-
native_start_time,
|
|
614
|
-
native_stop_time,
|
|
615
|
-
native_isip)
|
|
616
|
-
return stage_part
|
|
617
|
-
|
|
618
|
-
@staticmethod
|
|
619
|
-
def add_stage_part_to_stage(mutable_stage, stage_part):
|
|
620
|
-
"""
|
|
621
|
-
Add a newly created `stage_part` to a newly created `mutable_stage`.
|
|
622
|
-
|
|
623
|
-
This method exists primarily so that I can mock it for unit tests.
|
|
624
|
-
|
|
625
|
-
Args:
|
|
626
|
-
mutable_stage: The newly created stage supporting mutability.
|
|
627
|
-
stage_part: The newly created stage part.
|
|
628
|
-
"""
|
|
629
|
-
stage_parts = List[IStagePart]()
|
|
630
|
-
stage_parts.Add(stage_part)
|
|
631
|
-
mutable_stage.Parts = stage_parts
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Copyright 2017-2025 KAPPA
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
# This file is part of Orchid and related technologies.
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import option
|
|
20
|
-
|
|
21
|
-
from orchid import (
|
|
22
|
-
base,
|
|
23
|
-
dot_net_dom_access as dna,
|
|
24
|
-
dom_project_object as dpo,
|
|
25
|
-
measurement as om,
|
|
26
|
-
net_date_time as ndt,
|
|
27
|
-
net_quantity as onq,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class NativeStagePartAdapter(dpo.DomProjectObject):
|
|
32
|
-
def __init__(self, adaptee):
|
|
33
|
-
super().__init__(adaptee, base.constantly(adaptee.Project))
|
|
34
|
-
|
|
35
|
-
display_name_with_well = dna.dom_property('display_name_with_well',
|
|
36
|
-
'The display stage number including the well name')
|
|
37
|
-
display_name_without_well = dna.dom_property('display_name_without_well',
|
|
38
|
-
'The display stage number excluding the well name')
|
|
39
|
-
part_no = dna.dom_property('part_number', 'The part number for this stage part')
|
|
40
|
-
start_time = dna.transformed_dom_property('start_time', 'The start time of this stage part',
|
|
41
|
-
ndt.as_date_time)
|
|
42
|
-
stop_time = dna.transformed_dom_property('stop_time', 'The stop time of this stage part',
|
|
43
|
-
ndt.as_date_time)
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def isip(self) -> om.Quantity:
|
|
47
|
-
"""
|
|
48
|
-
Return the instantaneous shut-in pressure of this stage part in project units.
|
|
49
|
-
"""
|
|
50
|
-
return onq.as_measurement(self.expect_project_units.PRESSURE, option.maybe(self.dom_object.Isip))
|