orchid-python-api 5.25.3__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.3.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.3.dist-info → orchid_python_api-5.25.4.dist-info}/WHEEL +1 -1
- ReleaseNotes.md +0 -730
- 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.3.dist-info/LICENSE +0 -176
- orchid_python_api-5.25.3.dist-info/RECORD +0 -88
- {orchid_python_api-5.25.3.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/net_quantity.py
DELETED
|
@@ -1,620 +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
|
-
"""This module contains functions for converting between instances of the (Python) `Measurement` class and
|
|
19
|
-
instances of .NET classes like `UnitsNet.Quantity` and `DateTime`."""
|
|
20
|
-
|
|
21
|
-
from functools import singledispatch
|
|
22
|
-
import math
|
|
23
|
-
from numbers import Real
|
|
24
|
-
import operator
|
|
25
|
-
from typing import Optional, Union
|
|
26
|
-
|
|
27
|
-
import option
|
|
28
|
-
import toolz.curried as toolz
|
|
29
|
-
|
|
30
|
-
from orchid import (
|
|
31
|
-
measurement as om,
|
|
32
|
-
physical_quantity as opq,
|
|
33
|
-
unit_system as units,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
# noinspection PyUnresolvedReferences
|
|
37
|
-
from Optional import Option
|
|
38
|
-
# noinspection PyUnresolvedReferences
|
|
39
|
-
import System
|
|
40
|
-
# noinspection PyUnresolvedReferences
|
|
41
|
-
import UnitsNet
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# Convenience functions
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def to_net_quantity_value(magnitude):
|
|
48
|
-
"""
|
|
49
|
-
Create a `UnitsNet` `QuantityValue` instance.
|
|
50
|
-
|
|
51
|
-
The `UnitsNet` package *does not* accept floating point values to create most measurements; instead, these
|
|
52
|
-
creation functions expect an argument of type `QuantityValue`. In .NET, these values are created using an
|
|
53
|
-
implicit conversion. This implicit version on the Python side fails.
|
|
54
|
-
|
|
55
|
-
This function allows us to define that conversion in one place.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
magnitude: The magnitude of the `UnitNet` `Quantity` (measurement) to be created.
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
The `magnitude` wrapped in a `UnitsNet.QuantityValue` instance.
|
|
62
|
-
|
|
63
|
-
"""
|
|
64
|
-
return UnitsNet.QuantityValue.op_Implicit(magnitude)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def net_length_from(magnitude: float, net_unit: UnitsNet.Length.Units) -> UnitsNet.Quantity:
|
|
68
|
-
"""
|
|
69
|
-
Create a `UnitsNet` length measurement from `magnitude` and `net_unit`.
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
magnitude: The magnitude of the length measurement
|
|
73
|
-
net_unit: The `UnitsNet` unit of the length measurement
|
|
74
|
-
|
|
75
|
-
Returns:
|
|
76
|
-
The `UnitsNet` `Quantity` whose `Value` is `magnitude` and whose `Unit` is `net_unit`.
|
|
77
|
-
"""
|
|
78
|
-
return UnitsNet.Length.From(to_net_quantity_value(magnitude), net_unit)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def net_pressure_from(magnitude: float, net_unit: UnitsNet.Pressure.Units) -> UnitsNet.Quantity:
|
|
82
|
-
"""
|
|
83
|
-
Create a `UnitsNet` pressure measurement from `magnitude` and `net_unit`.
|
|
84
|
-
|
|
85
|
-
Args:
|
|
86
|
-
magnitude: The magnitude of the pressure measurement
|
|
87
|
-
net_unit: The `UnitsNet` unit of the pressure measurement
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
The `UnitsNet` `Quantity` whose `Value` is `magnitude` and whose `Unit` is `net_unit`.
|
|
91
|
-
"""
|
|
92
|
-
return UnitsNet.Pressure.From(to_net_quantity_value(magnitude), net_unit)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# The following code creates conversion functions programmatically by:
|
|
96
|
-
# - Creating a map from variable name to string identifying how to create the `UnitsNet` `Quantity`
|
|
97
|
-
# - Transforming that map by:
|
|
98
|
-
# - Transforming the map keys by prepending 'net_'
|
|
99
|
-
# - Transforming the map values to a function creating the value. (See the documentation of
|
|
100
|
-
# `operator.attrgetter` function for details.)
|
|
101
|
-
# - Adding the key and value of this map to the `globals()` dict (module attributes)
|
|
102
|
-
net_creator_attributes = {
|
|
103
|
-
'angle_from_deg': 'Angle.FromDegrees',
|
|
104
|
-
'duration_from_min': 'Duration.FromMinutes',
|
|
105
|
-
'density_from_lbs_per_cu_ft': 'Density.FromPoundsPerCubicFoot',
|
|
106
|
-
'density_from_kg_per_cu_m': 'Density.FromKilogramsPerCubicMeter',
|
|
107
|
-
'energy_from_ft_lbs': 'Energy.FromFootPounds',
|
|
108
|
-
'energy_from_J': 'Energy.FromJoules',
|
|
109
|
-
'force_from_lbf': 'Force.FromPoundsForce',
|
|
110
|
-
'force_from_N': 'Force.FromNewtons',
|
|
111
|
-
'length_from_ft': 'Length.FromFeet',
|
|
112
|
-
'length_from_m': 'Length.FromMeters',
|
|
113
|
-
'mass_from_lbs': 'Mass.FromPounds',
|
|
114
|
-
'mass_from_kg': 'Mass.FromKilograms',
|
|
115
|
-
'power_from_hp': 'Power.FromMechanicalHorsepower',
|
|
116
|
-
'power_from_W': 'Power.FromWatts',
|
|
117
|
-
'pressure_from_psi': 'Pressure.FromPoundsForcePerSquareInch',
|
|
118
|
-
'pressure_from_kPa': 'Pressure.FromKilopascals',
|
|
119
|
-
'pressure_from_bars': 'Pressure.FromBars',
|
|
120
|
-
'mass_concentration_from_lbs_per_gal': 'MassConcentration.FromPoundsPerUSGallon',
|
|
121
|
-
'mass_concentration_from_kg_per_cu_m': 'MassConcentration.FromKilogramsPerCubicMeter',
|
|
122
|
-
'volume_flow_from_oil_bbl_per_min': 'VolumeFlow.FromOilBarrelsPerMinute',
|
|
123
|
-
'volume_flow_from_cu_m_per_min': 'VolumeFlow.FromCubicMetersPerMinute',
|
|
124
|
-
'temperature_from_deg_F': 'Temperature.FromDegreesFahrenheit',
|
|
125
|
-
'temperature_from_deg_C': 'Temperature.FromDegreesCelsius',
|
|
126
|
-
'volume_from_oil_bbl': 'Volume.FromOilBarrels',
|
|
127
|
-
'volume_from_cu_m': 'Volume.FromCubicMeters',
|
|
128
|
-
}
|
|
129
|
-
net_creator_funcs = toolz.pipe(
|
|
130
|
-
net_creator_attributes,
|
|
131
|
-
toolz.keymap(lambda k: f'net_{k}'),
|
|
132
|
-
toolz.valmap(lambda v: toolz.compose(operator.attrgetter(v)(UnitsNet),
|
|
133
|
-
to_net_quantity_value)),
|
|
134
|
-
)
|
|
135
|
-
for variable_name, variable_value in net_creator_funcs.items():
|
|
136
|
-
globals()[variable_name] = variable_value
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class EqualsComparisonDetails:
|
|
140
|
-
def __init__(self, tolerance: Real = 1e-4,
|
|
141
|
-
net_comparison_type: UnitsNet.ComparisonType = UnitsNet.ComparisonType.Relative):
|
|
142
|
-
"""
|
|
143
|
-
Construct an instance that uses `tolerance` and `comparison_type` to determine equality.
|
|
144
|
-
|
|
145
|
-
This class exists because the `tolerance` and `comparison_type` are closely coupled; that is, one
|
|
146
|
-
cannot correctly interpret the use of `tolerance` without a reference to the `comparison_type`.
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
tolerance: The maximum difference tolerated between two instances in determining equality.
|
|
150
|
-
net_comparison_type: The type of comparison: `UnitsNet.ComparisonType.Relative` or
|
|
151
|
-
`UnitsNet.ComparisonType.Absolute`.
|
|
152
|
-
"""
|
|
153
|
-
self._tolerance = tolerance
|
|
154
|
-
self._comparison_type = net_comparison_type
|
|
155
|
-
|
|
156
|
-
@property
|
|
157
|
-
def tolerance(self) -> Real:
|
|
158
|
-
"""
|
|
159
|
-
Return the tolerance to be use in determining equality.
|
|
160
|
-
|
|
161
|
-
Although this property is public, it is intended only to be read by the `equal_net_comparison`
|
|
162
|
-
function.
|
|
163
|
-
"""
|
|
164
|
-
return self._tolerance
|
|
165
|
-
|
|
166
|
-
@property
|
|
167
|
-
def comparison_type(self) -> UnitsNet.ComparisonType:
|
|
168
|
-
"""
|
|
169
|
-
Return the comparison type to be use in determining equality.
|
|
170
|
-
|
|
171
|
-
Although this property is public, it is intended only to be read by the `equal_net_comparison`
|
|
172
|
-
function.
|
|
173
|
-
"""
|
|
174
|
-
return self._comparison_type
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
#
|
|
178
|
-
# Although Pint supports the unit `cu_ft`, we have chosen to use the synonym, `ft ** 3` (which is
|
|
179
|
-
# printed as 'ft\u00b3` (that is, 'ft' followed by a Unicode superscript 3)). According to a
|
|
180
|
-
# citation on [Wikipedia article](https://en.wikipedia.org/wiki/Cubic_foot), this "is the IEEE
|
|
181
|
-
# symbol for the cubic foot." Our general rule: we accept the Pint unit `cu_ft` as **input**,
|
|
182
|
-
# but, on various conversion, produce the Pint unit `ft**3`.
|
|
183
|
-
#
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
@singledispatch
|
|
187
|
-
@toolz.curry
|
|
188
|
-
def as_measurement(unknown, _maybe_net_quantity: option.Option[UnitsNet.IQuantity]) -> om.Quantity:
|
|
189
|
-
"""
|
|
190
|
-
Convert an optional .NET `IQuantity` to a `pint` `Quantity` instance.
|
|
191
|
-
|
|
192
|
-
This function is registered as the type-handler for the `object` type. In our situation, arriving here
|
|
193
|
-
indicates an error by an implementer and so raises an error.
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
unknown: A parameter whose type is not expected.
|
|
197
|
-
_maybe_net_quantity: The optional .NET `IQuantity` instance to convert. (Unused.)
|
|
198
|
-
"""
|
|
199
|
-
raise TypeError(f'First argument, {unknown}, has type {type(unknown)}, unexpected by `as_measurement`.')
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
# noinspection PyUnresolvedReferences
|
|
203
|
-
@as_measurement.register(units.Common)
|
|
204
|
-
@toolz.curry
|
|
205
|
-
def as_measurement_in_common_unit(target_unit, maybe_net_quantity: UnitsNet.IQuantity) -> om.Quantity:
|
|
206
|
-
"""
|
|
207
|
-
Convert an optional .NET `IQuantity` to a `pint` `Quantity` instance in a common unit.
|
|
208
|
-
|
|
209
|
-
Args:
|
|
210
|
-
target_unit: The unit (from the units.Common) for the converted `Quantity` instance.
|
|
211
|
-
maybe_net_quantity: The optional .NET `IQuantity` instance to convert.
|
|
212
|
-
|
|
213
|
-
Returns:
|
|
214
|
-
The equivalent `Quantity` instance in the target unit.
|
|
215
|
-
"""
|
|
216
|
-
return maybe_net_quantity.map_or(_as_measurement_in_unit(target_unit),
|
|
217
|
-
om.Quantity(float('NaN'), target_unit.value.unit))
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
@as_measurement.register(units.Metric)
|
|
221
|
-
@as_measurement.register(units.UsOilfield)
|
|
222
|
-
@toolz.curry
|
|
223
|
-
def as_measurement_in_specified_unit(target_unit,
|
|
224
|
-
maybe_net_quantity: option.Option[UnitsNet.IQuantity]) -> om.Quantity:
|
|
225
|
-
"""
|
|
226
|
-
Convert an optional .NET `IQuantity` to a `pint` `Quantity` instance.
|
|
227
|
-
|
|
228
|
-
Args:
|
|
229
|
-
target_unit: The unit for the converted `Quantity` instance.
|
|
230
|
-
maybe_net_quantity: The optional .NET `IQuantity` instance to convert.
|
|
231
|
-
|
|
232
|
-
Returns:
|
|
233
|
-
The equivalent `Quantity` instance in the target unit.
|
|
234
|
-
"""
|
|
235
|
-
|
|
236
|
-
result = maybe_net_quantity.map_or(_as_measurement_in_unit(target_unit),
|
|
237
|
-
om.Quantity(float('NaN'), target_unit.value.unit))
|
|
238
|
-
return result
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
@toolz.curry
|
|
242
|
-
def _as_measurement_in_unit(target_unit: Union[units.Metric, units.UsOilfield],
|
|
243
|
-
net_quantity: UnitsNet.IQuantity) -> om.Quantity:
|
|
244
|
-
"""
|
|
245
|
-
Convert an `IQuantity` to a `pint` `Quantity` in a specified compatible unit.
|
|
246
|
-
|
|
247
|
-
Args:
|
|
248
|
-
target_unit: The target unit for the converted `Quantity` instance.
|
|
249
|
-
net_quantity: The .NET `IQuantity` instance to convert.
|
|
250
|
-
|
|
251
|
-
Returns:
|
|
252
|
-
The equivalent `Quantity` instance in the specified unit.
|
|
253
|
-
"""
|
|
254
|
-
target_magnitude = net_quantity.As(_UNIT_NET_UNITS[target_unit])
|
|
255
|
-
result = om.Quantity(target_magnitude, target_unit.value.unit)
|
|
256
|
-
return result
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# noinspection PyUnresolvedReferences
|
|
260
|
-
_physical_quantity_to_net_physical_quantity = {
|
|
261
|
-
opq.PhysicalQuantity.ANGLE: UnitsNet.Angle,
|
|
262
|
-
opq.PhysicalQuantity.DURATION: UnitsNet.Duration,
|
|
263
|
-
opq.PhysicalQuantity.DENSITY: UnitsNet.Density,
|
|
264
|
-
opq.PhysicalQuantity.ENERGY: UnitsNet.Energy,
|
|
265
|
-
opq.PhysicalQuantity.FORCE: UnitsNet.Force,
|
|
266
|
-
opq.PhysicalQuantity.LENGTH: UnitsNet.Length,
|
|
267
|
-
opq.PhysicalQuantity.MASS: UnitsNet.Mass,
|
|
268
|
-
opq.PhysicalQuantity.POWER: UnitsNet.Power,
|
|
269
|
-
opq.PhysicalQuantity.PRESSURE: UnitsNet.Pressure,
|
|
270
|
-
opq.PhysicalQuantity.PROPPANT_CONCENTRATION: UnitsNet.MassConcentration,
|
|
271
|
-
opq.PhysicalQuantity.TEMPERATURE: UnitsNet.Temperature,
|
|
272
|
-
opq.PhysicalQuantity.SLURRY_RATE: UnitsNet.VolumeFlow,
|
|
273
|
-
opq.PhysicalQuantity.VOLUME: UnitsNet.Volume,
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
@toolz.curry
|
|
278
|
-
def _python_measurement_option(target_unit: Union[units.Metric, units.UsOilfield],
|
|
279
|
-
optional_net_quantity: Option[UnitsNet.IQuantity]):
|
|
280
|
-
@toolz.curry
|
|
281
|
-
def net_option_as_pythonic(net_option):
|
|
282
|
-
# If we are **not** an instance of `Option<Pressure>`
|
|
283
|
-
if not hasattr(net_option, 'HasValue'):
|
|
284
|
-
# Simply return the value (which may be `null` / `None`)
|
|
285
|
-
return net_option
|
|
286
|
-
|
|
287
|
-
# If we **are** an instance of `Option<Pressure>` yet have no value
|
|
288
|
-
if not net_option.HasValue:
|
|
289
|
-
return None
|
|
290
|
-
|
|
291
|
-
# The variable, `net_quantity`, will contain a zero value in the `UnitsNet` unit corresponding to the Python
|
|
292
|
-
# physical quantity of the `target_unit`. However, because of the preceding `if` statement, I expect this
|
|
293
|
-
# value to **not** be returned. (It is actually an error if it is returned; unfortunately, it is an
|
|
294
|
-
# undetectable error because I cannot distinguish the zero value from a zero value actually wrapped in
|
|
295
|
-
# the `Option<T>.Some` expression.
|
|
296
|
-
net_physical_quantity = _physical_quantity_to_net_physical_quantity[target_unit.value.physical_quantity]
|
|
297
|
-
result = net_option.ValueOr.Overloads[net_physical_quantity](net_physical_quantity.Zero)
|
|
298
|
-
return result
|
|
299
|
-
|
|
300
|
-
return toolz.pipe(
|
|
301
|
-
optional_net_quantity,
|
|
302
|
-
net_option_as_pythonic,
|
|
303
|
-
option.maybe,
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def as_measurement_from_option(target_unit: Union[units.Common, units.Metric, units.UsOilfield],
|
|
308
|
-
optional_net_quantity: Option[UnitsNet.IQuantity]):
|
|
309
|
-
maybe_python_measurement = _python_measurement_option(target_unit, optional_net_quantity)
|
|
310
|
-
return as_measurement(target_unit, maybe_python_measurement)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
@singledispatch
|
|
314
|
-
@toolz.curry
|
|
315
|
-
def as_net_quantity(unknown, _measurement: om.Quantity) -> Optional[UnitsNet.IQuantity]:
|
|
316
|
-
"""
|
|
317
|
-
Convert a .NET UnitsNet.IQuantity to a `pint` `Quantity` instance.
|
|
318
|
-
|
|
319
|
-
This function is registered as the type-handler for the `object` type. In our situation, arriving here
|
|
320
|
-
indicates an error by an implementer and so raises an error.
|
|
321
|
-
|
|
322
|
-
Args:
|
|
323
|
-
unknown: A parameter whose type is not expected.
|
|
324
|
-
_measurement: The `Quantity` instance to convert.
|
|
325
|
-
|
|
326
|
-
Returns:
|
|
327
|
-
The equivalent `UnitsNet.IQuantity` instance.
|
|
328
|
-
"""
|
|
329
|
-
raise TypeError(f'First argument, {unknown}, has type {type(unknown)}, unexpected by `as_net_quantity`.')
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
# noinspection PyUnresolvedReferences
|
|
333
|
-
_PINT_UNIT_CREATE_NET_UNITS = {
|
|
334
|
-
om.registry.deg: UnitsNet.Angle.FromDegrees,
|
|
335
|
-
om.registry.min: UnitsNet.Duration.FromMinutes,
|
|
336
|
-
om.registry.ft_lb: UnitsNet.Energy.FromFootPounds,
|
|
337
|
-
om.registry.J: UnitsNet.Energy.FromJoules,
|
|
338
|
-
om.registry.lbf: UnitsNet.Force.FromPoundsForce,
|
|
339
|
-
om.registry.N: UnitsNet.Force.FromNewtons,
|
|
340
|
-
om.registry.ft: UnitsNet.Length.FromFeet,
|
|
341
|
-
om.registry.m: UnitsNet.Length.FromMeters,
|
|
342
|
-
om.registry.lb: UnitsNet.Mass.FromPounds,
|
|
343
|
-
om.registry.kg: UnitsNet.Mass.FromKilograms,
|
|
344
|
-
om.registry.hp: UnitsNet.Power.FromMechanicalHorsepower,
|
|
345
|
-
om.registry.W: UnitsNet.Power.FromWatts,
|
|
346
|
-
om.registry.psi: UnitsNet.Pressure.FromPoundsForcePerSquareInch,
|
|
347
|
-
om.registry.kPa: UnitsNet.Pressure.FromKilopascals,
|
|
348
|
-
om.registry.oil_bbl / om.registry.min: net_volume_flow_from_oil_bbl_per_min,
|
|
349
|
-
((om.registry.m ** 3) / om.registry.min): net_volume_flow_from_cu_m_per_min,
|
|
350
|
-
om.registry.degF: UnitsNet.Temperature.FromDegreesFahrenheit,
|
|
351
|
-
om.registry.degC: UnitsNet.Temperature.FromDegreesCelsius,
|
|
352
|
-
om.registry.oil_bbl: UnitsNet.Volume.FromOilBarrels,
|
|
353
|
-
(om.registry.m ** 3): UnitsNet.Volume.FromCubicMeters,
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
def _us_oilfield_slurry_rate(qv):
|
|
358
|
-
return UnitsNet.Density.FromPoundsPerCubicFoot(qv)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
# noinspection PyUnresolvedReferences
|
|
362
|
-
_PHYSICAL_QUANTITY_PINT_UNIT_NET_UNITS = {
|
|
363
|
-
opq.PhysicalQuantity.DENSITY: {
|
|
364
|
-
om.registry.lb / om.registry.cu_ft: _us_oilfield_slurry_rate,
|
|
365
|
-
om.registry.lb / om.registry.ft ** 3: _us_oilfield_slurry_rate,
|
|
366
|
-
om.registry.kg / (om.registry.m ** 3): UnitsNet.Density.FromKilogramsPerCubicMeter,
|
|
367
|
-
},
|
|
368
|
-
opq.PhysicalQuantity.PROPPANT_CONCENTRATION: {
|
|
369
|
-
om.registry.lb / om.registry.gal: net_mass_concentration_from_lbs_per_gal,
|
|
370
|
-
om.registry.kg / (om.registry.m ** 3): net_mass_concentration_from_kg_per_cu_m,
|
|
371
|
-
},
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
# noinspection PyUnresolvedReferences
|
|
376
|
-
@as_net_quantity.register(opq.PhysicalQuantity)
|
|
377
|
-
@toolz.curry
|
|
378
|
-
def as_net_quantity_using_physical_quantity(physical_quantity,
|
|
379
|
-
measurement: om.Quantity) -> Optional[UnitsNet.IQuantity]:
|
|
380
|
-
"""
|
|
381
|
-
Convert a `Quantity` instance to a .NET `UnitsNet.IQuantity` instance.
|
|
382
|
-
|
|
383
|
-
Args:
|
|
384
|
-
physical_quantity: The `PhysicalQuantity`. Although we try to determine a unique mapping between units
|
|
385
|
-
in `pint` and .NET `UnitsNet` units, we cannot perform a unique mapping for density and proppant
|
|
386
|
-
concentration measured in the metric system (the units of both these physical quantities are
|
|
387
|
-
"kg/m**3").
|
|
388
|
-
measurement: The `Quantity` instance to convert.
|
|
389
|
-
|
|
390
|
-
Returns:
|
|
391
|
-
The equivalent `UnitsNet.IQuantity` instance.
|
|
392
|
-
"""
|
|
393
|
-
if math.isnan(measurement.magnitude):
|
|
394
|
-
return None
|
|
395
|
-
|
|
396
|
-
quantity = UnitsNet.QuantityValue.op_Implicit(measurement.magnitude)
|
|
397
|
-
if physical_quantity == opq.PhysicalQuantity.DENSITY:
|
|
398
|
-
return toolz.get_in([physical_quantity, measurement.units], _PHYSICAL_QUANTITY_PINT_UNIT_NET_UNITS)(quantity)
|
|
399
|
-
|
|
400
|
-
if physical_quantity == opq.PhysicalQuantity.PROPPANT_CONCENTRATION:
|
|
401
|
-
return toolz.get_in([physical_quantity, measurement.units],
|
|
402
|
-
_PHYSICAL_QUANTITY_PINT_UNIT_NET_UNITS)(measurement.magnitude)
|
|
403
|
-
|
|
404
|
-
if physical_quantity == opq.PhysicalQuantity.SLURRY_RATE:
|
|
405
|
-
return toolz.get(measurement.units, _PINT_UNIT_CREATE_NET_UNITS)(measurement.magnitude)
|
|
406
|
-
|
|
407
|
-
return toolz.get(measurement.units, _PINT_UNIT_CREATE_NET_UNITS)(quantity)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
# noinspection PyUnresolvedReferences
|
|
411
|
-
@as_net_quantity.register(units.Common)
|
|
412
|
-
@toolz.curry
|
|
413
|
-
def as_net_quantity_using_common_units(to_common_unit, measurement: om.Quantity) -> Optional[UnitsNet.IQuantity]:
|
|
414
|
-
"""
|
|
415
|
-
Convert a `Quantity` instance to a .NET `UnitsNet.IQuantity` instance corresponding `to_unit`.
|
|
416
|
-
|
|
417
|
-
Args:
|
|
418
|
-
to_common_unit: The target unit of measurement.
|
|
419
|
-
measurement: The `Quantity` instance to convert.
|
|
420
|
-
|
|
421
|
-
Returns:
|
|
422
|
-
The equivalent `UnitsNet.IQuantity` instance.
|
|
423
|
-
"""
|
|
424
|
-
# units.Common support no conversion so simply call another implementation.
|
|
425
|
-
return as_net_quantity(to_common_unit.value.physical_quantity, measurement)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
# noinspection PyUnresolvedReferences
|
|
429
|
-
@as_net_quantity.register(units.Metric)
|
|
430
|
-
@as_net_quantity.register(units.UsOilfield)
|
|
431
|
-
@toolz.curry
|
|
432
|
-
def as_net_quantity_in_specified_unit(specified_unit, measurement: om.Quantity) -> Optional[UnitsNet.IQuantity]:
|
|
433
|
-
"""
|
|
434
|
-
Convert a `pint` `Quantity` to a .NET UnitsNet.IQuantity instance in a specified, but compatible unit.
|
|
435
|
-
|
|
436
|
-
Args:
|
|
437
|
-
specified_unit: The unit for the converted `Quantity` instance.
|
|
438
|
-
measurement: The `Quantity` instance to convert.
|
|
439
|
-
|
|
440
|
-
Returns:
|
|
441
|
-
The equivalent `Quantity` instance in the specified unit.
|
|
442
|
-
"""
|
|
443
|
-
target_measurement = measurement.to(specified_unit.value.unit)
|
|
444
|
-
return as_net_quantity(specified_unit.value.physical_quantity, target_measurement)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
def equal_net_quantities(left_quantity: UnitsNet.IQuantity, right_quantity: UnitsNet.IQuantity,
|
|
448
|
-
comparison_details: EqualsComparisonDetails = EqualsComparisonDetails()):
|
|
449
|
-
"""
|
|
450
|
-
Compares two UnitsNet.IQuantity instances for equality
|
|
451
|
-
|
|
452
|
-
Python.NET transforms == (perhaps indirectly) into a call to Equals. Unfortunately, comparing
|
|
453
|
-
two measurements that have been transformed may have floating point differences. Specifically,
|
|
454
|
-
UnitsNet marks the `Equals` method as `Obsolete` with the following message:
|
|
455
|
-
> "It is not safe to compare equality due to using System.Double as the internal representation.
|
|
456
|
-
> It is very easy to get slightly different values due to floating point operations. Instead use
|
|
457
|
-
> Equals(Length, double, ComparisonType) to provide the max allowed absolute or relative error."
|
|
458
|
-
|
|
459
|
-
Consequently, to determine if two `UnitsNet.IQuantity` instances are equal, I use the
|
|
460
|
-
`Equals(Length, double, ComparisonType)` method applied to each instance.
|
|
461
|
-
|
|
462
|
-
Args:
|
|
463
|
-
left_quantity: The `IQuantity` instance on the "left-hand-side" of the (implicit) == operator.
|
|
464
|
-
right_quantity: The `IQuantity` instance on the "right-hand-side" of the (implicit) == operator.
|
|
465
|
-
comparison_details: The details of how to compare the two `UnitsNet.IQuantity` instances.
|
|
466
|
-
|
|
467
|
-
Returns:
|
|
468
|
-
|
|
469
|
-
"""
|
|
470
|
-
return left_quantity.Equals(right_quantity, comparison_details.tolerance, comparison_details.comparison_type)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
def net_decimal_to_float(net_decimal: System.Decimal) -> float:
|
|
474
|
-
"""
|
|
475
|
-
Convert a .NET Decimal value to a Python float.
|
|
476
|
-
|
|
477
|
-
Python.NET currently leaves .NET values of type `Decimal` unconverted. For example, UnitsNet models units
|
|
478
|
-
of the physical quantity, power, as values of type .NET 'QuantityValue` whose `Value` property returns a
|
|
479
|
-
value of .NET `Decimal` type. This function assists in converting those values to Python values of type
|
|
480
|
-
`float`.
|
|
481
|
-
|
|
482
|
-
Args:
|
|
483
|
-
net_decimal: The .NET `Decimal` value to convert.
|
|
484
|
-
|
|
485
|
-
Returns:
|
|
486
|
-
A value of type `float` that is "equivalent" to the .NET `Decimal` value. Note that this conversion is
|
|
487
|
-
"lossy" because .NET `Decimal` values are exact, but `float` values are not.
|
|
488
|
-
"""
|
|
489
|
-
return System.Decimal.ToDouble(net_decimal)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
_UNIT_NET_UNITS = {
|
|
493
|
-
units.Common.ANGLE: UnitsNet.Units.AngleUnit.Degree,
|
|
494
|
-
units.Common.DURATION: UnitsNet.Units.DurationUnit.Minute,
|
|
495
|
-
units.UsOilfield.DENSITY: UnitsNet.Units.DensityUnit.PoundPerCubicFoot,
|
|
496
|
-
units.Metric.DENSITY: UnitsNet.Units.DensityUnit.KilogramPerCubicMeter,
|
|
497
|
-
units.UsOilfield.ENERGY: UnitsNet.Units.EnergyUnit.FootPound,
|
|
498
|
-
units.Metric.ENERGY: UnitsNet.Units.EnergyUnit.Joule,
|
|
499
|
-
units.UsOilfield.FORCE: UnitsNet.Units.ForceUnit.PoundForce,
|
|
500
|
-
units.Metric.FORCE: UnitsNet.Units.ForceUnit.Newton,
|
|
501
|
-
units.UsOilfield.LENGTH: UnitsNet.Units.LengthUnit.Foot,
|
|
502
|
-
units.Metric.LENGTH: UnitsNet.Units.LengthUnit.Meter,
|
|
503
|
-
units.UsOilfield.MASS: UnitsNet.Units.MassUnit.Pound,
|
|
504
|
-
units.Metric.MASS: UnitsNet.Units.MassUnit.Kilogram,
|
|
505
|
-
units.UsOilfield.POWER: UnitsNet.Units.PowerUnit.MechanicalHorsepower,
|
|
506
|
-
units.Metric.POWER: UnitsNet.Units.PowerUnit.Watt,
|
|
507
|
-
units.UsOilfield.PRESSURE: UnitsNet.Units.PressureUnit.PoundForcePerSquareInch,
|
|
508
|
-
units.Metric.PRESSURE: UnitsNet.Units.PressureUnit.Kilopascal,
|
|
509
|
-
units.UsOilfield.PROPPANT_CONCENTRATION: UnitsNet.Units.MassConcentrationUnit.PoundPerUSGallon,
|
|
510
|
-
units.Metric.PROPPANT_CONCENTRATION: UnitsNet.Units.MassConcentrationUnit.KilogramPerCubicMeter,
|
|
511
|
-
units.UsOilfield.SLURRY_RATE: UnitsNet.Units.VolumeFlowUnit.OilBarrelPerMinute,
|
|
512
|
-
units.Metric.SLURRY_RATE: UnitsNet.Units.VolumeFlowUnit.CubicMeterPerMinute,
|
|
513
|
-
units.UsOilfield.TEMPERATURE: UnitsNet.Units.TemperatureUnit.DegreeFahrenheit,
|
|
514
|
-
units.Metric.TEMPERATURE: UnitsNet.Units.TemperatureUnit.DegreeCelsius,
|
|
515
|
-
units.UsOilfield.VOLUME: UnitsNet.Units.VolumeUnit.OilBarrel,
|
|
516
|
-
units.Metric.VOLUME: UnitsNet.Units.VolumeUnit.CubicMeter,
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
@toolz.curry
|
|
521
|
-
def _convert_net_quantity_to_different_unit(target_unit: units.UnitSystem,
|
|
522
|
-
net_quantity: UnitsNet.IQuantity) -> UnitsNet.IQuantity:
|
|
523
|
-
"""
|
|
524
|
-
Convert one .NET `UnitsNet.IQuantity` to another .NET `UnitsNet.IQuantity` in a different unit `target_unit`
|
|
525
|
-
Args:
|
|
526
|
-
net_quantity: The `UnitsNet.IQuantity` instance to convert.
|
|
527
|
-
target_unit: The unit to which to convert `maybe_net_quantity`.
|
|
528
|
-
|
|
529
|
-
Returns:
|
|
530
|
-
The .NET `UnitsNet.IQuantity` converted to `target_unit`.
|
|
531
|
-
"""
|
|
532
|
-
result = net_quantity.ToUnit(_UNIT_NET_UNITS[target_unit])
|
|
533
|
-
return result
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
def _net_decimal_to_float(net_decimal: System.Decimal) -> float:
|
|
537
|
-
"""
|
|
538
|
-
Convert a .NET Decimal value to a Python float.
|
|
539
|
-
|
|
540
|
-
Python.NET currently leaves .NET values of type `Decimal` unconverted. For example, UnitsNet models units
|
|
541
|
-
of the physical quantity, power, as values of type .NET 'QuantityValue` whose `Value` property returns a
|
|
542
|
-
value of .NET `Decimal` type. This function assists in converting those values to Python values of type
|
|
543
|
-
`float`.
|
|
544
|
-
|
|
545
|
-
Args:
|
|
546
|
-
net_decimal: The .NET `Decimal` value to convert.
|
|
547
|
-
|
|
548
|
-
Returns:
|
|
549
|
-
A value of type `float` that is "equivalent" to the .NET `Decimal` value. Note that this conversion is
|
|
550
|
-
"lossy" because .NET `Decimal` values are exact, but `float` values are not.
|
|
551
|
-
"""
|
|
552
|
-
return System.Decimal.ToDouble(net_decimal)
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
_PHYSICAL_QUANTITY_NET_UNIT_PINT_UNITS = {
|
|
556
|
-
opq.PhysicalQuantity.DENSITY: {
|
|
557
|
-
UnitsNet.Units.DensityUnit.PoundPerCubicFoot: om.registry.lb / om.registry.ft ** 3,
|
|
558
|
-
UnitsNet.Units.DensityUnit.KilogramPerCubicMeter: om.registry.kg / (om.registry.m ** 3),
|
|
559
|
-
},
|
|
560
|
-
opq.PhysicalQuantity.ENERGY: {
|
|
561
|
-
UnitsNet.Units.EnergyUnit.FootPound: om.registry.ft_lb,
|
|
562
|
-
UnitsNet.Units.EnergyUnit.Joule: om.registry.J,
|
|
563
|
-
},
|
|
564
|
-
opq.PhysicalQuantity.FORCE: {
|
|
565
|
-
UnitsNet.Units.ForceUnit.PoundForce: om.registry.lbf,
|
|
566
|
-
UnitsNet.Units.ForceUnit.Newton: om.registry.N,
|
|
567
|
-
},
|
|
568
|
-
opq.PhysicalQuantity.LENGTH: {
|
|
569
|
-
UnitsNet.Units.LengthUnit.Foot: om.registry.ft,
|
|
570
|
-
UnitsNet.Units.LengthUnit.Meter: om.registry.m,
|
|
571
|
-
},
|
|
572
|
-
opq.PhysicalQuantity.MASS: {
|
|
573
|
-
UnitsNet.Units.MassUnit.Pound: om.registry.lb,
|
|
574
|
-
UnitsNet.Units.MassUnit.Kilogram: om.registry.kg,
|
|
575
|
-
},
|
|
576
|
-
opq.PhysicalQuantity.POWER: {
|
|
577
|
-
UnitsNet.Units.PowerUnit.MechanicalHorsepower: om.registry.hp,
|
|
578
|
-
UnitsNet.Units.PowerUnit.Watt: om.registry.W,
|
|
579
|
-
},
|
|
580
|
-
opq.PhysicalQuantity.PRESSURE: {
|
|
581
|
-
UnitsNet.Units.PressureUnit.PoundForcePerSquareInch: om.registry.psi,
|
|
582
|
-
UnitsNet.Units.PressureUnit.Kilopascal: om.registry.kPa,
|
|
583
|
-
},
|
|
584
|
-
opq.PhysicalQuantity.PROPPANT_CONCENTRATION: {
|
|
585
|
-
UnitsNet.Units.MassConcentrationUnit.PoundPerUSGallon: om.registry.lb / om.registry.gallon,
|
|
586
|
-
UnitsNet.Units.MassConcentrationUnit.KilogramPerCubicMeter: om.registry.kg / om.registry.m ** 3,
|
|
587
|
-
},
|
|
588
|
-
opq.PhysicalQuantity.SLURRY_RATE: {
|
|
589
|
-
UnitsNet.Units.VolumeFlowUnit.OilBarrelPerMinute: om.registry.oil_bbl / om.registry.min,
|
|
590
|
-
UnitsNet.Units.VolumeFlowUnit.CubicMeterPerMinute: om.registry.m ** 3 / om.registry.min,
|
|
591
|
-
},
|
|
592
|
-
opq.PhysicalQuantity.TEMPERATURE: {
|
|
593
|
-
UnitsNet.Units.TemperatureUnit.DegreeFahrenheit: om.registry.degF,
|
|
594
|
-
UnitsNet.Units.TemperatureUnit.DegreeCelsius: om.registry.degC,
|
|
595
|
-
},
|
|
596
|
-
opq.PhysicalQuantity.VOLUME: {
|
|
597
|
-
UnitsNet.Units.VolumeUnit.OilBarrel: om.registry.oil_bbl,
|
|
598
|
-
UnitsNet.Units.VolumeUnit.CubicMeter: om.registry.m ** 3,
|
|
599
|
-
},
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
def _to_pint_unit(physical_quantity: opq.PhysicalQuantity, net_unit: UnitsNet.Units) -> om.Unit:
|
|
604
|
-
"""
|
|
605
|
-
Convert `net_unit`, a unit of measure for `physical_quantity`, to a `pint` unit.
|
|
606
|
-
|
|
607
|
-
Args:
|
|
608
|
-
physical_quantity: The physical quantity measured by `net_unit`.
|
|
609
|
-
net_unit: The .NET UnitsNet.Unit to be converted.
|
|
610
|
-
|
|
611
|
-
Returns:
|
|
612
|
-
The `pint` Unit corresponding to `net_unit`.
|
|
613
|
-
"""
|
|
614
|
-
result = toolz.get_in([physical_quantity, net_unit], _PHYSICAL_QUANTITY_NET_UNIT_PINT_UNITS)
|
|
615
|
-
if result is not None:
|
|
616
|
-
return result
|
|
617
|
-
elif physical_quantity == opq.PhysicalQuantity.ANGLE:
|
|
618
|
-
return om.registry.deg
|
|
619
|
-
elif physical_quantity == opq.PhysicalQuantity.DURATION:
|
|
620
|
-
return om.registry.min
|
orchid/net_stage_qc.py
DELETED
|
@@ -1,62 +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
|
-
Expose constants to the Orchid Python API.
|
|
20
|
-
|
|
21
|
-
The .NET stage QC "class" implementation depends upon a number of constants. This module exposes those constants to the
|
|
22
|
-
Orchid Python API.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
import enum
|
|
26
|
-
import uuid
|
|
27
|
-
|
|
28
|
-
import toolz.curried as toolz
|
|
29
|
-
|
|
30
|
-
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
|
31
|
-
from Orchid.FractureDiagnostics import CorrectionStatus as NetCorrectionStatus
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class CorrectionStatus(enum.Enum):
|
|
35
|
-
# TODO: Change to use .NET `Enum` member.
|
|
36
|
-
# Python.NET always transforms .NET `Enum` members into Python `int` values. This transformation is a known issue
|
|
37
|
-
# (https://github.com/pythonnet/pythonnet/issues/1220). The Python.NET team has corrected the issue but only for
|
|
38
|
-
# Python.NET 3.x; it has no plans for a backport.
|
|
39
|
-
#
|
|
40
|
-
# Although I have successfully use the Python.NET transformation of .NET `Enum` members to `ints`; I have
|
|
41
|
-
# encountered issues with its usage in .NET `Variant` types which is used for stage QC information.
|
|
42
|
-
#
|
|
43
|
-
# To simplify the "work-around" implemented in `native_stage_qc_adapter`, I use the hard-coded string value of
|
|
44
|
-
# .NET `CorrectionStatus`.
|
|
45
|
-
#
|
|
46
|
-
# See also the Jupyter notebook, `features/notebooks/explore_stage_qc.py`, for attempts to use the .NET `Enum`.
|
|
47
|
-
CONFIRMED = 'Confirmed'
|
|
48
|
-
NEW = 'New'
|
|
49
|
-
UNCONFIRMED = 'Unconfirmed'
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class StageQCTags(enum.Enum):
|
|
53
|
-
QC_NOTES = 'stage_qc_notes'
|
|
54
|
-
START_STOP_CONFIRMATION = 'stage_start_stop_confirmation'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def make_key(stage_id: uuid.UUID, tag: StageQCTags) -> str:
|
|
58
|
-
return f'{str(stage_id)}|{tag.value}'
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
make_start_stop_confirmation_key = toolz.flip(make_key)(StageQCTags.START_STOP_CONFIRMATION)
|
|
62
|
-
make_qc_notes_key = toolz.flip(make_key)(StageQCTags.QC_NOTES)
|