well-log-toolkit 0.1.149__py3-none-any.whl → 0.1.150__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.
- well_log_toolkit/manager.py +110 -5
- well_log_toolkit/property.py +10 -4
- {well_log_toolkit-0.1.149.dist-info → well_log_toolkit-0.1.150.dist-info}/METADATA +1 -1
- {well_log_toolkit-0.1.149.dist-info → well_log_toolkit-0.1.150.dist-info}/RECORD +6 -6
- {well_log_toolkit-0.1.149.dist-info → well_log_toolkit-0.1.150.dist-info}/WHEEL +0 -0
- {well_log_toolkit-0.1.149.dist-info → well_log_toolkit-0.1.150.dist-info}/top_level.txt +0 -0
well_log_toolkit/manager.py
CHANGED
|
@@ -1445,12 +1445,23 @@ class _ManagerPropertyProxy:
|
|
|
1445
1445
|
prop = prop.filter(filter_name, source=source_name)
|
|
1446
1446
|
|
|
1447
1447
|
# Compute sums_avg
|
|
1448
|
-
|
|
1448
|
+
result = prop.sums_avg(
|
|
1449
1449
|
weighted=weighted,
|
|
1450
1450
|
arithmetic=arithmetic,
|
|
1451
1451
|
precision=precision
|
|
1452
1452
|
)
|
|
1453
1453
|
|
|
1454
|
+
# Add well-level thickness for this source if using filter_intervals
|
|
1455
|
+
if self._custom_intervals and result:
|
|
1456
|
+
well_thickness = 0.0
|
|
1457
|
+
for key, value in result.items():
|
|
1458
|
+
if isinstance(value, dict) and 'thickness' in value:
|
|
1459
|
+
well_thickness += value['thickness']
|
|
1460
|
+
if well_thickness > 0:
|
|
1461
|
+
result['thickness'] = round(well_thickness, precision)
|
|
1462
|
+
|
|
1463
|
+
source_results[source_name] = result
|
|
1464
|
+
|
|
1454
1465
|
except (PropertyNotFoundError, PropertyTypeError, AttributeError, KeyError, ValueError):
|
|
1455
1466
|
# Property or filter doesn't exist in this source, or filter isn't discrete - skip it
|
|
1456
1467
|
pass
|
|
@@ -1476,12 +1487,23 @@ class _ManagerPropertyProxy:
|
|
|
1476
1487
|
prop = prop.filter(filter_name)
|
|
1477
1488
|
|
|
1478
1489
|
# Compute sums_avg
|
|
1479
|
-
|
|
1490
|
+
result = prop.sums_avg(
|
|
1480
1491
|
weighted=weighted,
|
|
1481
1492
|
arithmetic=arithmetic,
|
|
1482
1493
|
precision=precision
|
|
1483
1494
|
)
|
|
1484
1495
|
|
|
1496
|
+
# Add well-level thickness (sum of all zone thicknesses) if using filter_intervals
|
|
1497
|
+
if self._custom_intervals and result:
|
|
1498
|
+
well_thickness = 0.0
|
|
1499
|
+
for key, value in result.items():
|
|
1500
|
+
if isinstance(value, dict) and 'thickness' in value:
|
|
1501
|
+
well_thickness += value['thickness']
|
|
1502
|
+
if well_thickness > 0:
|
|
1503
|
+
result['thickness'] = round(well_thickness, precision)
|
|
1504
|
+
|
|
1505
|
+
return result
|
|
1506
|
+
|
|
1485
1507
|
except PropertyNotFoundError as e:
|
|
1486
1508
|
# Check if it's ambiguous (exists in multiple sources)
|
|
1487
1509
|
if "ambiguous" in str(e).lower():
|
|
@@ -1512,6 +1534,16 @@ class _ManagerPropertyProxy:
|
|
|
1512
1534
|
arithmetic=arithmetic,
|
|
1513
1535
|
precision=precision
|
|
1514
1536
|
)
|
|
1537
|
+
|
|
1538
|
+
# Add well-level thickness for this source if using filter_intervals
|
|
1539
|
+
if self._custom_intervals and result:
|
|
1540
|
+
well_thickness = 0.0
|
|
1541
|
+
for key, value in result.items():
|
|
1542
|
+
if isinstance(value, dict) and 'thickness' in value:
|
|
1543
|
+
well_thickness += value['thickness']
|
|
1544
|
+
if well_thickness > 0:
|
|
1545
|
+
result['thickness'] = round(well_thickness, precision)
|
|
1546
|
+
|
|
1515
1547
|
source_results[source_name] = result
|
|
1516
1548
|
|
|
1517
1549
|
except (PropertyNotFoundError, PropertyTypeError, AttributeError, KeyError, ValueError):
|
|
@@ -1632,7 +1664,7 @@ class _ManagerMultiPropertyProxy:
|
|
|
1632
1664
|
PROPERTY_STATS = {'mean', 'median', 'mode', 'sum', 'std_dev', 'percentile', 'range'}
|
|
1633
1665
|
|
|
1634
1666
|
# Stats that are common across properties (stay at group level)
|
|
1635
|
-
COMMON_STATS = {'depth_range', 'samples', 'thickness', '
|
|
1667
|
+
COMMON_STATS = {'depth_range', 'samples', 'thickness', 'thickness_fraction', 'calculation'}
|
|
1636
1668
|
|
|
1637
1669
|
def __init__(
|
|
1638
1670
|
self,
|
|
@@ -1849,7 +1881,17 @@ class _ManagerMultiPropertyProxy:
|
|
|
1849
1881
|
return self._merge_flat_results(property_results)
|
|
1850
1882
|
|
|
1851
1883
|
# Merge results: nest property-specific stats, keep common stats at group level
|
|
1852
|
-
|
|
1884
|
+
merged = self._merge_property_results(property_results)
|
|
1885
|
+
|
|
1886
|
+
# Add well-level thickness (sum of all zone thicknesses)
|
|
1887
|
+
if self._custom_intervals and merged:
|
|
1888
|
+
well_thickness = 0.0
|
|
1889
|
+
for key, value in merged.items():
|
|
1890
|
+
if isinstance(value, dict) and 'thickness' in value:
|
|
1891
|
+
well_thickness += value['thickness']
|
|
1892
|
+
merged['thickness'] = round(well_thickness, 6)
|
|
1893
|
+
|
|
1894
|
+
return merged
|
|
1853
1895
|
|
|
1854
1896
|
def _apply_filter_intervals(self, prop, well):
|
|
1855
1897
|
"""
|
|
@@ -3108,7 +3150,70 @@ class WellDataManager:
|
|
|
3108
3150
|
['well_12_3_2_B', 'well_12_3_2_A']
|
|
3109
3151
|
"""
|
|
3110
3152
|
return list(self._wells.keys())
|
|
3111
|
-
|
|
3153
|
+
|
|
3154
|
+
@property
|
|
3155
|
+
def saved_intervals(self) -> dict[str, list[str]]:
|
|
3156
|
+
"""
|
|
3157
|
+
List saved interval names for all wells.
|
|
3158
|
+
|
|
3159
|
+
Returns
|
|
3160
|
+
-------
|
|
3161
|
+
dict[str, list[str]]
|
|
3162
|
+
Dictionary mapping well names to their saved interval names
|
|
3163
|
+
|
|
3164
|
+
Examples
|
|
3165
|
+
--------
|
|
3166
|
+
>>> manager.saved_intervals
|
|
3167
|
+
{'well_A': ['Reservoir_Zones', 'Slump_Zones'], 'well_B': ['Reservoir_Zones']}
|
|
3168
|
+
"""
|
|
3169
|
+
result = {}
|
|
3170
|
+
for well_name, well in self._wells.items():
|
|
3171
|
+
if well.saved_intervals:
|
|
3172
|
+
result[well_name] = well.saved_intervals
|
|
3173
|
+
return result
|
|
3174
|
+
|
|
3175
|
+
def get_intervals(self, name: str) -> dict[str, list[dict]]:
|
|
3176
|
+
"""
|
|
3177
|
+
Get saved filter intervals by name from all wells that have them.
|
|
3178
|
+
|
|
3179
|
+
Parameters
|
|
3180
|
+
----------
|
|
3181
|
+
name : str
|
|
3182
|
+
Name of the saved filter intervals
|
|
3183
|
+
|
|
3184
|
+
Returns
|
|
3185
|
+
-------
|
|
3186
|
+
dict[str, list[dict]]
|
|
3187
|
+
Dictionary mapping well names to their interval definitions
|
|
3188
|
+
|
|
3189
|
+
Raises
|
|
3190
|
+
------
|
|
3191
|
+
KeyError
|
|
3192
|
+
If no wells have intervals with the given name
|
|
3193
|
+
|
|
3194
|
+
Examples
|
|
3195
|
+
--------
|
|
3196
|
+
>>> manager.get_intervals("Slump_Zones")
|
|
3197
|
+
{'well_A': [{'name': 'Zone_A', 'top': 2500, 'base': 2650}],
|
|
3198
|
+
'well_B': [{'name': 'Zone_A', 'top': 2600, 'base': 2750}]}
|
|
3199
|
+
"""
|
|
3200
|
+
result = {}
|
|
3201
|
+
for well_name, well in self._wells.items():
|
|
3202
|
+
if name in well.saved_intervals:
|
|
3203
|
+
result[well_name] = well.get_intervals(name)
|
|
3204
|
+
|
|
3205
|
+
if not result:
|
|
3206
|
+
# Collect all available interval names for error message
|
|
3207
|
+
all_names = set()
|
|
3208
|
+
for well in self._wells.values():
|
|
3209
|
+
all_names.update(well.saved_intervals)
|
|
3210
|
+
raise KeyError(
|
|
3211
|
+
f"No wells have saved intervals named '{name}'. "
|
|
3212
|
+
f"Available: {sorted(all_names) if all_names else 'none'}"
|
|
3213
|
+
)
|
|
3214
|
+
|
|
3215
|
+
return result
|
|
3216
|
+
|
|
3112
3217
|
def get_well(self, name: str) -> Well:
|
|
3113
3218
|
"""
|
|
3114
3219
|
Get well by original or sanitized name.
|
well_log_toolkit/property.py
CHANGED
|
@@ -1779,24 +1779,31 @@ class Property(PropertyOperationsMixin):
|
|
|
1779
1779
|
# contributes to this zone (even boundary samples with partial intervals)
|
|
1780
1780
|
interval_mask = zone_intervals > 0
|
|
1781
1781
|
|
|
1782
|
+
# Calculate zone thickness (sum of valid intervals within zone)
|
|
1783
|
+
valid_mask = interval_mask & ~np.isnan(self.values)
|
|
1784
|
+
zone_thickness = float(np.sum(zone_intervals[valid_mask]))
|
|
1785
|
+
|
|
1782
1786
|
# If there are secondary properties, group within this interval
|
|
1783
1787
|
if self.secondary_properties:
|
|
1784
|
-
|
|
1788
|
+
interval_result = self._recursive_group(
|
|
1785
1789
|
0,
|
|
1786
1790
|
interval_mask,
|
|
1787
1791
|
weighted=weighted,
|
|
1788
1792
|
arithmetic=arithmetic,
|
|
1789
|
-
gross_thickness=
|
|
1793
|
+
gross_thickness=zone_thickness, # Pass zone thickness as gross for children
|
|
1790
1794
|
precision=precision,
|
|
1791
1795
|
zone_intervals=zone_intervals
|
|
1792
1796
|
)
|
|
1797
|
+
# Add zone-level thickness
|
|
1798
|
+
interval_result['thickness'] = round(zone_thickness, precision)
|
|
1799
|
+
result[interval_name] = interval_result
|
|
1793
1800
|
else:
|
|
1794
1801
|
# No secondary properties, compute stats directly for interval
|
|
1795
1802
|
result[interval_name] = self._compute_stats(
|
|
1796
1803
|
interval_mask,
|
|
1797
1804
|
weighted=weighted,
|
|
1798
1805
|
arithmetic=arithmetic,
|
|
1799
|
-
gross_thickness=
|
|
1806
|
+
gross_thickness=zone_thickness, # Use zone thickness for fraction calc
|
|
1800
1807
|
precision=precision,
|
|
1801
1808
|
zone_intervals=zone_intervals
|
|
1802
1809
|
)
|
|
@@ -2416,7 +2423,6 @@ class Property(PropertyOperationsMixin):
|
|
|
2416
2423
|
'depth_range': _round_value(depth_range_dict),
|
|
2417
2424
|
'samples': int(len(valid)),
|
|
2418
2425
|
'thickness': round(thickness, precision),
|
|
2419
|
-
'gross_thickness': round(gross_thickness, precision),
|
|
2420
2426
|
'thickness_fraction': round(fraction, precision),
|
|
2421
2427
|
'calculation': calc_method,
|
|
2422
2428
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
well_log_toolkit/__init__.py,sha256=ilJAIIhh68pYfD9I3V53juTEJpoMN8oHpcpEFNpuXAQ,3793
|
|
2
2
|
well_log_toolkit/exceptions.py,sha256=X_fzC7d4yaBFO9Vx74dEIB6xmI9Agi6_bTU3MPxn6ko,985
|
|
3
3
|
well_log_toolkit/las_file.py,sha256=Tj0mRfX1aX2s6uug7BBlY1m_mu3G50EGxHGzD0eEedE,53876
|
|
4
|
-
well_log_toolkit/manager.py,sha256=
|
|
4
|
+
well_log_toolkit/manager.py,sha256=F6C8SXSD53FtG16-u3z298ViAj-5cMeNLSAoU77MyXY,140694
|
|
5
5
|
well_log_toolkit/operations.py,sha256=z8j8fGBOwoJGUQFy-Vawjq9nm3OD_dUt0oaNh8yuG7o,18515
|
|
6
|
-
well_log_toolkit/property.py,sha256=
|
|
6
|
+
well_log_toolkit/property.py,sha256=XY3BAN76CY6KY8na4iyoz6P-inhDyb821o3gN7ZC3q4,104184
|
|
7
7
|
well_log_toolkit/regression.py,sha256=JDcRxaODJnFikAdPJyTq8eUV7iY0vCDmvnGufqlojxs,31625
|
|
8
8
|
well_log_toolkit/statistics.py,sha256=cpUbaRGlqyqpGWKtETk9XpXWrMJIIjVacdqEqIBkvqQ,19118
|
|
9
9
|
well_log_toolkit/utils.py,sha256=O2KPq4htIoUlL74V2zKftdqqTjRfezU9M-568zPLme0,6866
|
|
10
10
|
well_log_toolkit/visualization.py,sha256=nnpmFmbj44TbP0fsnLMR1GaKRkqKCEpI6Fd8Cp0oqBc,204716
|
|
11
11
|
well_log_toolkit/well.py,sha256=n6XfaGSjGtyXCIaAr0ytslIK0DMUY_fSPQ_VCqj8jaU,106173
|
|
12
|
-
well_log_toolkit-0.1.
|
|
13
|
-
well_log_toolkit-0.1.
|
|
14
|
-
well_log_toolkit-0.1.
|
|
15
|
-
well_log_toolkit-0.1.
|
|
12
|
+
well_log_toolkit-0.1.150.dist-info/METADATA,sha256=I5J-CdMD7XIL0uhVhHnergVpoFxblRISMCT5KumaiU8,63473
|
|
13
|
+
well_log_toolkit-0.1.150.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
well_log_toolkit-0.1.150.dist-info/top_level.txt,sha256=BMOo7OKLcZEnjo0wOLMclwzwTbYKYh31I8RGDOGSBdE,17
|
|
15
|
+
well_log_toolkit-0.1.150.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|