well-log-toolkit 0.1.147__py3-none-any.whl → 0.1.148__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 +109 -9
- {well_log_toolkit-0.1.147.dist-info → well_log_toolkit-0.1.148.dist-info}/METADATA +1 -1
- {well_log_toolkit-0.1.147.dist-info → well_log_toolkit-0.1.148.dist-info}/RECORD +5 -5
- {well_log_toolkit-0.1.147.dist-info → well_log_toolkit-0.1.148.dist-info}/WHEEL +0 -0
- {well_log_toolkit-0.1.147.dist-info → well_log_toolkit-0.1.148.dist-info}/top_level.txt +0 -0
well_log_toolkit/manager.py
CHANGED
|
@@ -1646,6 +1646,19 @@ class _ManagerMultiPropertyProxy:
|
|
|
1646
1646
|
self._filters = filters or []
|
|
1647
1647
|
self._custom_intervals = custom_intervals
|
|
1648
1648
|
|
|
1649
|
+
def __getattr__(self, name: str) -> '_ManagerMultiPropertyProxy':
|
|
1650
|
+
"""
|
|
1651
|
+
Attribute access as shorthand for filter().
|
|
1652
|
+
|
|
1653
|
+
Allows: manager.properties(['A', 'B']).Facies.sums_avg()
|
|
1654
|
+
Same as: manager.properties(['A', 'B']).filter('Facies').sums_avg()
|
|
1655
|
+
"""
|
|
1656
|
+
# Avoid recursion for private attributes
|
|
1657
|
+
if name.startswith('_'):
|
|
1658
|
+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
|
|
1659
|
+
# Treat as filter
|
|
1660
|
+
return self.filter(name)
|
|
1661
|
+
|
|
1649
1662
|
def filter(
|
|
1650
1663
|
self,
|
|
1651
1664
|
property_name: str,
|
|
@@ -1759,13 +1772,10 @@ class _ManagerMultiPropertyProxy:
|
|
|
1759
1772
|
|
|
1760
1773
|
>>> manager.properties(['PHIE', 'PERM']).filter_intervals("Zones").sums_avg()
|
|
1761
1774
|
>>> # Returns stats for both properties grouped by custom intervals
|
|
1762
|
-
"""
|
|
1763
|
-
if not self._filters and not self._custom_intervals:
|
|
1764
|
-
raise ValueError(
|
|
1765
|
-
"sums_avg() requires at least one filter or filter_intervals(). "
|
|
1766
|
-
"Use .filter('property_name') or .filter_intervals(...) first."
|
|
1767
|
-
)
|
|
1768
1775
|
|
|
1776
|
+
>>> # No filters - compute stats for full well
|
|
1777
|
+
>>> manager.properties(['PHIE', 'PERM']).sums_avg()
|
|
1778
|
+
"""
|
|
1769
1779
|
result = {}
|
|
1770
1780
|
|
|
1771
1781
|
for well_name, well in self._manager._wells.items():
|
|
@@ -1787,6 +1797,18 @@ class _ManagerMultiPropertyProxy:
|
|
|
1787
1797
|
"""
|
|
1788
1798
|
Compute multi-property sums_avg for a single well.
|
|
1789
1799
|
"""
|
|
1800
|
+
# Check if this well has the required saved intervals (if using saved name)
|
|
1801
|
+
if self._custom_intervals:
|
|
1802
|
+
intervals = self._custom_intervals.get('intervals')
|
|
1803
|
+
if isinstance(intervals, str):
|
|
1804
|
+
# Saved filter name - check if this well has it
|
|
1805
|
+
if intervals not in well._saved_filter_intervals:
|
|
1806
|
+
return None # Skip wells that don't have this saved filter
|
|
1807
|
+
elif isinstance(intervals, dict):
|
|
1808
|
+
# Well-specific intervals - check if this well is in the dict
|
|
1809
|
+
if well.name not in intervals and well.sanitized_name not in intervals:
|
|
1810
|
+
return None # Skip wells not in the dict
|
|
1811
|
+
|
|
1790
1812
|
# Collect results for each property
|
|
1791
1813
|
property_results = {}
|
|
1792
1814
|
|
|
@@ -1798,7 +1820,7 @@ class _ManagerMultiPropertyProxy:
|
|
|
1798
1820
|
if self._custom_intervals:
|
|
1799
1821
|
prop = self._apply_filter_intervals(prop, well)
|
|
1800
1822
|
if prop is None:
|
|
1801
|
-
|
|
1823
|
+
continue # Skip this property if intervals can't be applied
|
|
1802
1824
|
|
|
1803
1825
|
# Apply all filters
|
|
1804
1826
|
for filter_name, insert_boundaries in self._filters:
|
|
@@ -1815,13 +1837,17 @@ class _ManagerMultiPropertyProxy:
|
|
|
1815
1837
|
)
|
|
1816
1838
|
property_results[prop_name] = result
|
|
1817
1839
|
|
|
1818
|
-
except (PropertyNotFoundError, PropertyTypeError, AttributeError, KeyError
|
|
1819
|
-
# Property doesn't exist in this well, skip it
|
|
1840
|
+
except (PropertyNotFoundError, PropertyTypeError, AttributeError, KeyError):
|
|
1841
|
+
# Property doesn't exist in this well or filter error, skip it
|
|
1820
1842
|
pass
|
|
1821
1843
|
|
|
1822
1844
|
if not property_results:
|
|
1823
1845
|
return None
|
|
1824
1846
|
|
|
1847
|
+
# If no filters/intervals, return simple merged result (no grouping)
|
|
1848
|
+
if not self._filters and not self._custom_intervals:
|
|
1849
|
+
return self._merge_flat_results(property_results)
|
|
1850
|
+
|
|
1825
1851
|
# Merge results: nest property-specific stats, keep common stats at group level
|
|
1826
1852
|
return self._merge_property_results(property_results)
|
|
1827
1853
|
|
|
@@ -1869,6 +1895,54 @@ class _ManagerMultiPropertyProxy:
|
|
|
1869
1895
|
save=save
|
|
1870
1896
|
)
|
|
1871
1897
|
|
|
1898
|
+
def _merge_flat_results(self, property_results: dict) -> dict:
|
|
1899
|
+
"""
|
|
1900
|
+
Merge results when no filters are applied (flat structure).
|
|
1901
|
+
|
|
1902
|
+
Returns a single dict with property-specific stats nested under property
|
|
1903
|
+
names and common stats at the top level.
|
|
1904
|
+
|
|
1905
|
+
Parameters
|
|
1906
|
+
----------
|
|
1907
|
+
property_results : dict
|
|
1908
|
+
{property_name: sums_avg_result}
|
|
1909
|
+
|
|
1910
|
+
Returns
|
|
1911
|
+
-------
|
|
1912
|
+
dict
|
|
1913
|
+
{
|
|
1914
|
+
"PropertyA": {"mean": ..., "median": ..., ...},
|
|
1915
|
+
"PropertyB": {"mean": ..., ...},
|
|
1916
|
+
"depth_range": {...},
|
|
1917
|
+
"samples": ...,
|
|
1918
|
+
...
|
|
1919
|
+
}
|
|
1920
|
+
"""
|
|
1921
|
+
if not property_results:
|
|
1922
|
+
return {}
|
|
1923
|
+
|
|
1924
|
+
result = {}
|
|
1925
|
+
|
|
1926
|
+
# Add property-specific stats for each property
|
|
1927
|
+
for prop_name, prop_result in property_results.items():
|
|
1928
|
+
if isinstance(prop_result, dict):
|
|
1929
|
+
# Extract property-specific stats
|
|
1930
|
+
prop_stats = {
|
|
1931
|
+
k: v for k, v in prop_result.items()
|
|
1932
|
+
if k in self.PROPERTY_STATS
|
|
1933
|
+
}
|
|
1934
|
+
if prop_stats:
|
|
1935
|
+
result[prop_name] = prop_stats
|
|
1936
|
+
|
|
1937
|
+
# Add common stats from first property
|
|
1938
|
+
first_result = next(iter(property_results.values()))
|
|
1939
|
+
if isinstance(first_result, dict):
|
|
1940
|
+
for k, v in first_result.items():
|
|
1941
|
+
if k in self.COMMON_STATS:
|
|
1942
|
+
result[k] = v
|
|
1943
|
+
|
|
1944
|
+
return result
|
|
1945
|
+
|
|
1872
1946
|
def _merge_property_results(self, property_results: dict) -> dict:
|
|
1873
1947
|
"""
|
|
1874
1948
|
Merge results from multiple properties.
|
|
@@ -2867,6 +2941,18 @@ class WellDataManager:
|
|
|
2867
2941
|
# Delete sources marked for deletion
|
|
2868
2942
|
well.delete_marked_sources(well_folder)
|
|
2869
2943
|
|
|
2944
|
+
# Save filter intervals if any exist
|
|
2945
|
+
if hasattr(well, '_saved_filter_intervals') and well._saved_filter_intervals:
|
|
2946
|
+
import json
|
|
2947
|
+
intervals_file = well_folder / "intervals.json"
|
|
2948
|
+
with open(intervals_file, 'w') as f:
|
|
2949
|
+
json.dump(well._saved_filter_intervals, f, indent=2)
|
|
2950
|
+
else:
|
|
2951
|
+
# Remove intervals file if no intervals (in case they were deleted)
|
|
2952
|
+
intervals_file = well_folder / "intervals.json"
|
|
2953
|
+
if intervals_file.exists():
|
|
2954
|
+
intervals_file.unlink()
|
|
2955
|
+
|
|
2870
2956
|
# Save templates
|
|
2871
2957
|
if self._templates:
|
|
2872
2958
|
templates_folder = save_path / "templates"
|
|
@@ -2957,6 +3043,20 @@ class WellDataManager:
|
|
|
2957
3043
|
for las_file in las_files:
|
|
2958
3044
|
self.load_las(las_file, silent=True)
|
|
2959
3045
|
|
|
3046
|
+
# Load saved filter intervals if they exist
|
|
3047
|
+
intervals_file = well_folder / "intervals.json"
|
|
3048
|
+
if intervals_file.exists():
|
|
3049
|
+
import json
|
|
3050
|
+
try:
|
|
3051
|
+
with open(intervals_file, 'r') as f:
|
|
3052
|
+
saved_intervals = json.load(f)
|
|
3053
|
+
# Find the well for this folder and set its intervals
|
|
3054
|
+
well_key = well_folder.name # e.g., "well_35_9_16_A"
|
|
3055
|
+
if well_key in self._wells:
|
|
3056
|
+
self._wells[well_key]._saved_filter_intervals = saved_intervals
|
|
3057
|
+
except Exception as e:
|
|
3058
|
+
warnings.warn(f"Could not load intervals from {intervals_file}: {e}")
|
|
3059
|
+
|
|
2960
3060
|
return self
|
|
2961
3061
|
|
|
2962
3062
|
def add_well(self, well_name: str) -> Well:
|
|
@@ -1,7 +1,7 @@
|
|
|
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=Jx0w1KpxRB2Oex6bC0FQFZOlJkoTKNexW3HMXxndL68,136713
|
|
5
5
|
well_log_toolkit/operations.py,sha256=z8j8fGBOwoJGUQFy-Vawjq9nm3OD_dUt0oaNh8yuG7o,18515
|
|
6
6
|
well_log_toolkit/property.py,sha256=GsiD9c4SfBw8ar7ZJXS0NNejPlpvFRHKck_eBR2lLmo,100965
|
|
7
7
|
well_log_toolkit/regression.py,sha256=JDcRxaODJnFikAdPJyTq8eUV7iY0vCDmvnGufqlojxs,31625
|
|
@@ -9,7 +9,7 @@ well_log_toolkit/statistics.py,sha256=_huPMbv2H3o9ezunjEM94mJknX5wPK8V4nDv2lIZZR
|
|
|
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.148.dist-info/METADATA,sha256=k7HnPCJ1iza1s8kvTFazQhfvYziyfVQ24JJYxWjrtvQ,63473
|
|
13
|
+
well_log_toolkit-0.1.148.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
well_log_toolkit-0.1.148.dist-info/top_level.txt,sha256=BMOo7OKLcZEnjo0wOLMclwzwTbYKYh31I8RGDOGSBdE,17
|
|
15
|
+
well_log_toolkit-0.1.148.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|