well-log-toolkit 0.1.146__py3-none-any.whl → 0.1.147__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 +394 -0
- well_log_toolkit/property.py +4 -0
- {well_log_toolkit-0.1.146.dist-info → well_log_toolkit-0.1.147.dist-info}/METADATA +1 -1
- {well_log_toolkit-0.1.146.dist-info → well_log_toolkit-0.1.147.dist-info}/RECORD +6 -6
- {well_log_toolkit-0.1.146.dist-info → well_log_toolkit-0.1.147.dist-info}/WHEEL +0 -0
- {well_log_toolkit-0.1.146.dist-info → well_log_toolkit-0.1.147.dist-info}/top_level.txt +0 -0
well_log_toolkit/manager.py
CHANGED
|
@@ -1618,6 +1618,346 @@ class _ManagerPropertyProxy:
|
|
|
1618
1618
|
)
|
|
1619
1619
|
|
|
1620
1620
|
|
|
1621
|
+
class _ManagerMultiPropertyProxy:
|
|
1622
|
+
"""
|
|
1623
|
+
Proxy for computing statistics across multiple properties on all wells.
|
|
1624
|
+
|
|
1625
|
+
Supports filter(), filter_intervals(), and sums_avg() methods.
|
|
1626
|
+
Multi-property results nest property-specific stats under property names
|
|
1627
|
+
while keeping common stats (depth_range, samples, thickness, etc.) at
|
|
1628
|
+
the group level.
|
|
1629
|
+
"""
|
|
1630
|
+
|
|
1631
|
+
# Stats that are specific to each property (nested under property name)
|
|
1632
|
+
PROPERTY_STATS = {'mean', 'median', 'mode', 'sum', 'std_dev', 'percentile', 'range'}
|
|
1633
|
+
|
|
1634
|
+
# Stats that are common across properties (stay at group level)
|
|
1635
|
+
COMMON_STATS = {'depth_range', 'samples', 'thickness', 'gross_thickness', 'thickness_fraction', 'calculation'}
|
|
1636
|
+
|
|
1637
|
+
def __init__(
|
|
1638
|
+
self,
|
|
1639
|
+
manager: 'WellDataManager',
|
|
1640
|
+
property_names: list[str],
|
|
1641
|
+
filters: Optional[list[tuple]] = None,
|
|
1642
|
+
custom_intervals: Optional[dict] = None
|
|
1643
|
+
):
|
|
1644
|
+
self._manager = manager
|
|
1645
|
+
self._property_names = property_names
|
|
1646
|
+
self._filters = filters or []
|
|
1647
|
+
self._custom_intervals = custom_intervals
|
|
1648
|
+
|
|
1649
|
+
def filter(
|
|
1650
|
+
self,
|
|
1651
|
+
property_name: str,
|
|
1652
|
+
insert_boundaries: Optional[bool] = None
|
|
1653
|
+
) -> '_ManagerMultiPropertyProxy':
|
|
1654
|
+
"""
|
|
1655
|
+
Add a filter (discrete property) to group statistics by.
|
|
1656
|
+
|
|
1657
|
+
Parameters
|
|
1658
|
+
----------
|
|
1659
|
+
property_name : str
|
|
1660
|
+
Name of discrete property to group by
|
|
1661
|
+
insert_boundaries : bool, optional
|
|
1662
|
+
Whether to insert boundary values at filter transitions
|
|
1663
|
+
|
|
1664
|
+
Returns
|
|
1665
|
+
-------
|
|
1666
|
+
_ManagerMultiPropertyProxy
|
|
1667
|
+
New proxy with filter added
|
|
1668
|
+
"""
|
|
1669
|
+
new_filters = self._filters + [(property_name, insert_boundaries)]
|
|
1670
|
+
return _ManagerMultiPropertyProxy(
|
|
1671
|
+
self._manager, self._property_names, new_filters, self._custom_intervals
|
|
1672
|
+
)
|
|
1673
|
+
|
|
1674
|
+
def filter_intervals(
|
|
1675
|
+
self,
|
|
1676
|
+
intervals: Union[str, list, dict],
|
|
1677
|
+
name: str = "Custom_Intervals",
|
|
1678
|
+
insert_boundaries: Optional[bool] = None,
|
|
1679
|
+
save: Optional[str] = None
|
|
1680
|
+
) -> '_ManagerMultiPropertyProxy':
|
|
1681
|
+
"""
|
|
1682
|
+
Filter by custom depth intervals.
|
|
1683
|
+
|
|
1684
|
+
Parameters
|
|
1685
|
+
----------
|
|
1686
|
+
intervals : str, list, or dict
|
|
1687
|
+
- str: Name of saved intervals to retrieve from each well
|
|
1688
|
+
- list: List of interval dicts [{"name": "Zone_A", "top": 2500, "base": 2700}, ...]
|
|
1689
|
+
- dict: Well-specific intervals {"well_name": [...], ...}
|
|
1690
|
+
name : str, default "Custom_Intervals"
|
|
1691
|
+
Name for the interval filter in results
|
|
1692
|
+
insert_boundaries : bool, optional
|
|
1693
|
+
Whether to insert boundary values at interval edges
|
|
1694
|
+
save : str, optional
|
|
1695
|
+
If provided, save intervals to wells with this name
|
|
1696
|
+
|
|
1697
|
+
Returns
|
|
1698
|
+
-------
|
|
1699
|
+
_ManagerMultiPropertyProxy
|
|
1700
|
+
New proxy with custom intervals set
|
|
1701
|
+
"""
|
|
1702
|
+
intervals_config = {
|
|
1703
|
+
'intervals': intervals,
|
|
1704
|
+
'name': name,
|
|
1705
|
+
'insert_boundaries': insert_boundaries,
|
|
1706
|
+
'save': save
|
|
1707
|
+
}
|
|
1708
|
+
return _ManagerMultiPropertyProxy(
|
|
1709
|
+
self._manager, self._property_names, self._filters, intervals_config
|
|
1710
|
+
)
|
|
1711
|
+
|
|
1712
|
+
def sums_avg(
|
|
1713
|
+
self,
|
|
1714
|
+
weighted: Optional[bool] = None,
|
|
1715
|
+
arithmetic: Optional[bool] = None,
|
|
1716
|
+
precision: int = 6
|
|
1717
|
+
) -> dict:
|
|
1718
|
+
"""
|
|
1719
|
+
Compute statistics for multiple properties across all wells.
|
|
1720
|
+
|
|
1721
|
+
Multi-property results nest property-specific stats (mean, median, etc.)
|
|
1722
|
+
under each property name, while common stats (depth_range, samples,
|
|
1723
|
+
thickness, etc.) remain at the group level.
|
|
1724
|
+
|
|
1725
|
+
Parameters
|
|
1726
|
+
----------
|
|
1727
|
+
weighted : bool, optional
|
|
1728
|
+
Include depth-weighted statistics.
|
|
1729
|
+
Default: True for continuous/discrete, False for sampled
|
|
1730
|
+
arithmetic : bool, optional
|
|
1731
|
+
Include arithmetic (unweighted) statistics.
|
|
1732
|
+
Default: False for continuous/discrete, True for sampled
|
|
1733
|
+
precision : int, default 6
|
|
1734
|
+
Number of decimal places for rounding numeric results
|
|
1735
|
+
|
|
1736
|
+
Returns
|
|
1737
|
+
-------
|
|
1738
|
+
dict
|
|
1739
|
+
Nested dictionary with structure:
|
|
1740
|
+
{
|
|
1741
|
+
"well_name": {
|
|
1742
|
+
"interval_name": { # if using filter_intervals
|
|
1743
|
+
"filter_value": {
|
|
1744
|
+
"PropertyA": {"mean": ..., "median": ..., ...},
|
|
1745
|
+
"PropertyB": {"mean": ..., "median": ..., ...},
|
|
1746
|
+
"depth_range": {...},
|
|
1747
|
+
"samples": ...,
|
|
1748
|
+
"thickness": ...,
|
|
1749
|
+
...
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
Examples
|
|
1756
|
+
--------
|
|
1757
|
+
>>> manager.properties(['PHIE', 'PERM']).filter('Facies').sums_avg()
|
|
1758
|
+
>>> # Returns stats for both properties grouped by facies
|
|
1759
|
+
|
|
1760
|
+
>>> manager.properties(['PHIE', 'PERM']).filter_intervals("Zones").sums_avg()
|
|
1761
|
+
>>> # 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
|
+
|
|
1769
|
+
result = {}
|
|
1770
|
+
|
|
1771
|
+
for well_name, well in self._manager._wells.items():
|
|
1772
|
+
well_result = self._compute_sums_avg_for_well(
|
|
1773
|
+
well, weighted, arithmetic, precision
|
|
1774
|
+
)
|
|
1775
|
+
if well_result is not None:
|
|
1776
|
+
result[well_name] = well_result
|
|
1777
|
+
|
|
1778
|
+
return _sanitize_for_json(result)
|
|
1779
|
+
|
|
1780
|
+
def _compute_sums_avg_for_well(
|
|
1781
|
+
self,
|
|
1782
|
+
well,
|
|
1783
|
+
weighted: Optional[bool],
|
|
1784
|
+
arithmetic: Optional[bool],
|
|
1785
|
+
precision: int
|
|
1786
|
+
):
|
|
1787
|
+
"""
|
|
1788
|
+
Compute multi-property sums_avg for a single well.
|
|
1789
|
+
"""
|
|
1790
|
+
# Collect results for each property
|
|
1791
|
+
property_results = {}
|
|
1792
|
+
|
|
1793
|
+
for prop_name in self._property_names:
|
|
1794
|
+
try:
|
|
1795
|
+
prop = well.get_property(prop_name)
|
|
1796
|
+
|
|
1797
|
+
# Apply filter_intervals if set
|
|
1798
|
+
if self._custom_intervals:
|
|
1799
|
+
prop = self._apply_filter_intervals(prop, well)
|
|
1800
|
+
if prop is None:
|
|
1801
|
+
return None # Well doesn't have the saved intervals
|
|
1802
|
+
|
|
1803
|
+
# Apply all filters
|
|
1804
|
+
for filter_name, insert_boundaries in self._filters:
|
|
1805
|
+
if insert_boundaries is not None:
|
|
1806
|
+
prop = prop.filter(filter_name, insert_boundaries=insert_boundaries)
|
|
1807
|
+
else:
|
|
1808
|
+
prop = prop.filter(filter_name)
|
|
1809
|
+
|
|
1810
|
+
# Compute sums_avg
|
|
1811
|
+
result = prop.sums_avg(
|
|
1812
|
+
weighted=weighted,
|
|
1813
|
+
arithmetic=arithmetic,
|
|
1814
|
+
precision=precision
|
|
1815
|
+
)
|
|
1816
|
+
property_results[prop_name] = result
|
|
1817
|
+
|
|
1818
|
+
except (PropertyNotFoundError, PropertyTypeError, AttributeError, KeyError, ValueError):
|
|
1819
|
+
# Property doesn't exist in this well, skip it
|
|
1820
|
+
pass
|
|
1821
|
+
|
|
1822
|
+
if not property_results:
|
|
1823
|
+
return None
|
|
1824
|
+
|
|
1825
|
+
# Merge results: nest property-specific stats, keep common stats at group level
|
|
1826
|
+
return self._merge_property_results(property_results)
|
|
1827
|
+
|
|
1828
|
+
def _apply_filter_intervals(self, prop, well):
|
|
1829
|
+
"""
|
|
1830
|
+
Apply filter_intervals to a property if custom_intervals is set.
|
|
1831
|
+
|
|
1832
|
+
Returns None if the well doesn't have the required saved intervals.
|
|
1833
|
+
"""
|
|
1834
|
+
if not self._custom_intervals:
|
|
1835
|
+
return prop
|
|
1836
|
+
|
|
1837
|
+
intervals_config = self._custom_intervals
|
|
1838
|
+
intervals = intervals_config['intervals']
|
|
1839
|
+
name = intervals_config['name']
|
|
1840
|
+
insert_boundaries = intervals_config['insert_boundaries']
|
|
1841
|
+
save = intervals_config['save']
|
|
1842
|
+
|
|
1843
|
+
# Resolve intervals for this well
|
|
1844
|
+
if isinstance(intervals, str):
|
|
1845
|
+
# Saved filter name - check if this well has it
|
|
1846
|
+
if intervals not in well._saved_filter_intervals:
|
|
1847
|
+
return None # Skip wells that don't have this saved filter
|
|
1848
|
+
well_intervals = intervals
|
|
1849
|
+
elif isinstance(intervals, dict):
|
|
1850
|
+
# Well-specific intervals
|
|
1851
|
+
well_intervals = None
|
|
1852
|
+
if well.name in intervals:
|
|
1853
|
+
well_intervals = intervals[well.name]
|
|
1854
|
+
elif well.sanitized_name in intervals:
|
|
1855
|
+
well_intervals = intervals[well.sanitized_name]
|
|
1856
|
+
if well_intervals is None:
|
|
1857
|
+
return None # Skip wells not in the dict
|
|
1858
|
+
elif isinstance(intervals, list):
|
|
1859
|
+
# Direct list of intervals
|
|
1860
|
+
well_intervals = intervals
|
|
1861
|
+
else:
|
|
1862
|
+
return None
|
|
1863
|
+
|
|
1864
|
+
# Apply filter_intervals
|
|
1865
|
+
return prop.filter_intervals(
|
|
1866
|
+
well_intervals,
|
|
1867
|
+
name=name,
|
|
1868
|
+
insert_boundaries=insert_boundaries,
|
|
1869
|
+
save=save
|
|
1870
|
+
)
|
|
1871
|
+
|
|
1872
|
+
def _merge_property_results(self, property_results: dict) -> dict:
|
|
1873
|
+
"""
|
|
1874
|
+
Merge results from multiple properties.
|
|
1875
|
+
|
|
1876
|
+
Nests property-specific stats under property names while keeping
|
|
1877
|
+
common stats at the group level.
|
|
1878
|
+
|
|
1879
|
+
Parameters
|
|
1880
|
+
----------
|
|
1881
|
+
property_results : dict
|
|
1882
|
+
{property_name: sums_avg_result}
|
|
1883
|
+
|
|
1884
|
+
Returns
|
|
1885
|
+
-------
|
|
1886
|
+
dict
|
|
1887
|
+
Merged result with structure:
|
|
1888
|
+
{
|
|
1889
|
+
"group_value": {
|
|
1890
|
+
"PropertyA": {"mean": ..., ...},
|
|
1891
|
+
"PropertyB": {"mean": ..., ...},
|
|
1892
|
+
"depth_range": {...},
|
|
1893
|
+
"samples": ...,
|
|
1894
|
+
...
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
"""
|
|
1898
|
+
if not property_results:
|
|
1899
|
+
return {}
|
|
1900
|
+
|
|
1901
|
+
# Use first property result as the structure template
|
|
1902
|
+
first_prop = next(iter(property_results.keys()))
|
|
1903
|
+
first_result = property_results[first_prop]
|
|
1904
|
+
|
|
1905
|
+
return self._merge_recursive(property_results, first_result)
|
|
1906
|
+
|
|
1907
|
+
def _merge_recursive(self, property_results: dict, template: dict) -> dict:
|
|
1908
|
+
"""
|
|
1909
|
+
Recursively merge property results following the template structure.
|
|
1910
|
+
"""
|
|
1911
|
+
result = {}
|
|
1912
|
+
|
|
1913
|
+
for key, value in template.items():
|
|
1914
|
+
if isinstance(value, dict):
|
|
1915
|
+
# Check if this is a stats dict (has property-specific keys)
|
|
1916
|
+
if any(k in value for k in self.PROPERTY_STATS):
|
|
1917
|
+
# This is a leaf stats dict - merge property stats here
|
|
1918
|
+
merged = {}
|
|
1919
|
+
|
|
1920
|
+
# Add property-specific stats for each property
|
|
1921
|
+
for prop_name, prop_result in property_results.items():
|
|
1922
|
+
# Navigate to the same key in this property's result
|
|
1923
|
+
prop_value = self._get_nested_value(prop_result, key)
|
|
1924
|
+
if prop_value and isinstance(prop_value, dict):
|
|
1925
|
+
# Extract property-specific stats
|
|
1926
|
+
prop_stats = {
|
|
1927
|
+
k: v for k, v in prop_value.items()
|
|
1928
|
+
if k in self.PROPERTY_STATS
|
|
1929
|
+
}
|
|
1930
|
+
if prop_stats:
|
|
1931
|
+
merged[prop_name] = prop_stats
|
|
1932
|
+
|
|
1933
|
+
# Add common stats from the first property
|
|
1934
|
+
for k, v in value.items():
|
|
1935
|
+
if k in self.COMMON_STATS:
|
|
1936
|
+
merged[k] = v
|
|
1937
|
+
|
|
1938
|
+
result[key] = merged
|
|
1939
|
+
else:
|
|
1940
|
+
# This is an intermediate nesting level - recurse
|
|
1941
|
+
# Collect corresponding sub-dicts from all properties
|
|
1942
|
+
sub_property_results = {}
|
|
1943
|
+
for prop_name, prop_result in property_results.items():
|
|
1944
|
+
prop_value = self._get_nested_value(prop_result, key)
|
|
1945
|
+
if prop_value and isinstance(prop_value, dict):
|
|
1946
|
+
sub_property_results[prop_name] = prop_value
|
|
1947
|
+
|
|
1948
|
+
if sub_property_results:
|
|
1949
|
+
result[key] = self._merge_recursive(sub_property_results, value)
|
|
1950
|
+
else:
|
|
1951
|
+
# Non-dict value, just copy from template
|
|
1952
|
+
result[key] = value
|
|
1953
|
+
|
|
1954
|
+
return result
|
|
1955
|
+
|
|
1956
|
+
def _get_nested_value(self, d: dict, key: str):
|
|
1957
|
+
"""Get value from dict, returning None if key doesn't exist."""
|
|
1958
|
+
return d.get(key) if isinstance(d, dict) else None
|
|
1959
|
+
|
|
1960
|
+
|
|
1621
1961
|
class WellDataManager:
|
|
1622
1962
|
"""
|
|
1623
1963
|
Global orchestrator for multi-well analysis.
|
|
@@ -1710,6 +2050,60 @@ class WellDataManager:
|
|
|
1710
2050
|
# Return a proxy that can be used for operations across all wells
|
|
1711
2051
|
return _ManagerPropertyProxy(self, name)
|
|
1712
2052
|
|
|
2053
|
+
def properties(self, property_names: list[str]) -> _ManagerMultiPropertyProxy:
|
|
2054
|
+
"""
|
|
2055
|
+
Create a multi-property proxy for computing statistics across multiple properties.
|
|
2056
|
+
|
|
2057
|
+
This allows computing statistics for multiple properties at once, with
|
|
2058
|
+
property-specific stats (mean, median, etc.) nested under property names
|
|
2059
|
+
and common stats (depth_range, samples, thickness, etc.) at the group level.
|
|
2060
|
+
|
|
2061
|
+
Parameters
|
|
2062
|
+
----------
|
|
2063
|
+
property_names : list[str]
|
|
2064
|
+
List of property names to include in statistics
|
|
2065
|
+
|
|
2066
|
+
Returns
|
|
2067
|
+
-------
|
|
2068
|
+
_ManagerMultiPropertyProxy
|
|
2069
|
+
Proxy that supports filter(), filter_intervals(), and sums_avg()
|
|
2070
|
+
|
|
2071
|
+
Examples
|
|
2072
|
+
--------
|
|
2073
|
+
>>> # Compute stats for multiple properties grouped by facies
|
|
2074
|
+
>>> manager.properties(['PHIE', 'PERM']).filter('Facies').sums_avg()
|
|
2075
|
+
>>> # Returns:
|
|
2076
|
+
>>> # {
|
|
2077
|
+
>>> # "well_A": {
|
|
2078
|
+
>>> # "Sand": {
|
|
2079
|
+
>>> # "PHIE": {"mean": 0.18, "median": 0.17, ...},
|
|
2080
|
+
>>> # "PERM": {"mean": 150, "median": 120, ...},
|
|
2081
|
+
>>> # "depth_range": {...},
|
|
2082
|
+
>>> # "samples": 387,
|
|
2083
|
+
>>> # "thickness": 29.4,
|
|
2084
|
+
>>> # ...
|
|
2085
|
+
>>> # }
|
|
2086
|
+
>>> # }
|
|
2087
|
+
>>> # }
|
|
2088
|
+
|
|
2089
|
+
>>> # With custom intervals
|
|
2090
|
+
>>> manager.properties(['PHIE', 'PERM']).filter('Facies').filter_intervals("Zones").sums_avg()
|
|
2091
|
+
>>> # Returns:
|
|
2092
|
+
>>> # {
|
|
2093
|
+
>>> # "well_A": {
|
|
2094
|
+
>>> # "Zone_1": {
|
|
2095
|
+
>>> # "Sand": {
|
|
2096
|
+
>>> # "PHIE": {"mean": 0.18, ...},
|
|
2097
|
+
>>> # "PERM": {"mean": 150, ...},
|
|
2098
|
+
>>> # "depth_range": {...},
|
|
2099
|
+
>>> # ...
|
|
2100
|
+
>>> # }
|
|
2101
|
+
>>> # }
|
|
2102
|
+
>>> # }
|
|
2103
|
+
>>> # }
|
|
2104
|
+
"""
|
|
2105
|
+
return _ManagerMultiPropertyProxy(self, property_names)
|
|
2106
|
+
|
|
1713
2107
|
def load_las(
|
|
1714
2108
|
self,
|
|
1715
2109
|
filepath: Union[str, Path, list[Union[str, Path]]],
|
well_log_toolkit/property.py
CHANGED
|
@@ -1165,6 +1165,10 @@ class Property(PropertyOperationsMixin):
|
|
|
1165
1165
|
new_prop._original_sample_count = len(self.depth)
|
|
1166
1166
|
new_prop._boundary_samples_inserted = len(new_depth) - len(self.depth)
|
|
1167
1167
|
|
|
1168
|
+
# Preserve custom intervals if they exist (from filter_intervals)
|
|
1169
|
+
if hasattr(self, '_custom_intervals') and self._custom_intervals:
|
|
1170
|
+
new_prop._custom_intervals = self._custom_intervals
|
|
1171
|
+
|
|
1168
1172
|
return new_prop
|
|
1169
1173
|
|
|
1170
1174
|
def filter_intervals(
|
|
@@ -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=WQHzNOXj7jVLeQlWG_uqfd93qemi5Mbe__z9NQRqk_Y,132563
|
|
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=GsiD9c4SfBw8ar7ZJXS0NNejPlpvFRHKck_eBR2lLmo,100965
|
|
7
7
|
well_log_toolkit/regression.py,sha256=JDcRxaODJnFikAdPJyTq8eUV7iY0vCDmvnGufqlojxs,31625
|
|
8
8
|
well_log_toolkit/statistics.py,sha256=_huPMbv2H3o9ezunjEM94mJknX5wPK8V4nDv2lIZZRw,16814
|
|
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.147.dist-info/METADATA,sha256=U89SvoBEewtJiCSN0ZNvevh1UGV__w7-8C3YGGIQZUM,63473
|
|
13
|
+
well_log_toolkit-0.1.147.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
well_log_toolkit-0.1.147.dist-info/top_level.txt,sha256=BMOo7OKLcZEnjo0wOLMclwzwTbYKYh31I8RGDOGSBdE,17
|
|
15
|
+
well_log_toolkit-0.1.147.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|