well-log-toolkit 0.1.139__tar.gz → 0.1.141__tar.gz
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-0.1.139 → well_log_toolkit-0.1.141}/PKG-INFO +1 -1
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/pyproject.toml +1 -1
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/property.py +225 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/visualization.py +66 -9
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/PKG-INFO +1 -1
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/README.md +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/setup.cfg +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/__init__.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/exceptions.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/las_file.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/manager.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/operations.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/regression.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/statistics.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/utils.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit/well.py +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/SOURCES.txt +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/dependency_links.txt +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/requires.txt +0 -0
- {well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "well-log-toolkit"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.141"
|
|
8
8
|
description = "Fast LAS file processing with lazy loading and filtering for well log analysis"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -1520,6 +1520,231 @@ class Property(PropertyOperationsMixin):
|
|
|
1520
1520
|
precision=precision
|
|
1521
1521
|
)
|
|
1522
1522
|
|
|
1523
|
+
def discrete_summary(self, precision: int = 6) -> dict:
|
|
1524
|
+
"""
|
|
1525
|
+
Compute summary statistics for discrete/categorical properties.
|
|
1526
|
+
|
|
1527
|
+
This method is designed for discrete logs (like facies, lithology flags,
|
|
1528
|
+
or net/gross indicators) where categorical statistics are more meaningful
|
|
1529
|
+
than continuous statistics like mean or standard deviation.
|
|
1530
|
+
|
|
1531
|
+
Parameters
|
|
1532
|
+
----------
|
|
1533
|
+
precision : int, default 6
|
|
1534
|
+
Number of decimal places for rounding numeric results
|
|
1535
|
+
|
|
1536
|
+
Returns
|
|
1537
|
+
-------
|
|
1538
|
+
dict
|
|
1539
|
+
Nested dictionary with statistics for each discrete value.
|
|
1540
|
+
If secondary properties (filters) exist, the structure is hierarchical.
|
|
1541
|
+
|
|
1542
|
+
For each discrete value, includes:
|
|
1543
|
+
- label: Human-readable name (if labels defined)
|
|
1544
|
+
- code: Numeric code for this category
|
|
1545
|
+
- count: Number of samples with this value
|
|
1546
|
+
- thickness: Total depth interval (meters) for this category
|
|
1547
|
+
- fraction: Proportion of total thickness (0-1)
|
|
1548
|
+
- depth_range: {min, max} depth extent
|
|
1549
|
+
|
|
1550
|
+
Examples
|
|
1551
|
+
--------
|
|
1552
|
+
>>> # Simple discrete summary (no filters)
|
|
1553
|
+
>>> facies = well.get_property('Facies')
|
|
1554
|
+
>>> stats = facies.discrete_summary()
|
|
1555
|
+
>>> # {'Sand': {'code': 1, 'count': 150, 'thickness': 25.5, 'fraction': 0.45, ...},
|
|
1556
|
+
>>> # 'Shale': {'code': 2, 'count': 180, 'thickness': 30.8, 'fraction': 0.55, ...}}
|
|
1557
|
+
|
|
1558
|
+
>>> # Grouped by zones
|
|
1559
|
+
>>> filtered = facies.filter('Well_Tops')
|
|
1560
|
+
>>> stats = filtered.discrete_summary()
|
|
1561
|
+
>>> # {'Zone_A': {'Sand': {...}, 'Shale': {...}},
|
|
1562
|
+
>>> # 'Zone_B': {'Sand': {...}, 'Shale': {...}}}
|
|
1563
|
+
|
|
1564
|
+
Notes
|
|
1565
|
+
-----
|
|
1566
|
+
For continuous properties, use `sums_avg()` instead.
|
|
1567
|
+
"""
|
|
1568
|
+
# Calculate gross thickness for fraction calculation
|
|
1569
|
+
full_intervals = compute_intervals(self.depth)
|
|
1570
|
+
valid_mask = ~np.isnan(self.values)
|
|
1571
|
+
gross_thickness = float(np.sum(full_intervals[valid_mask]))
|
|
1572
|
+
|
|
1573
|
+
if not self.secondary_properties:
|
|
1574
|
+
# No filters, compute stats for all discrete values
|
|
1575
|
+
return self._compute_discrete_stats(
|
|
1576
|
+
np.ones(len(self.depth), dtype=bool),
|
|
1577
|
+
gross_thickness=gross_thickness,
|
|
1578
|
+
precision=precision
|
|
1579
|
+
)
|
|
1580
|
+
|
|
1581
|
+
# Build hierarchical grouping
|
|
1582
|
+
return self._recursive_discrete_group(
|
|
1583
|
+
0,
|
|
1584
|
+
np.ones(len(self.depth), dtype=bool),
|
|
1585
|
+
gross_thickness=gross_thickness,
|
|
1586
|
+
precision=precision
|
|
1587
|
+
)
|
|
1588
|
+
|
|
1589
|
+
def _recursive_discrete_group(
|
|
1590
|
+
self,
|
|
1591
|
+
filter_idx: int,
|
|
1592
|
+
mask: np.ndarray,
|
|
1593
|
+
gross_thickness: float,
|
|
1594
|
+
precision: int = 6
|
|
1595
|
+
) -> dict:
|
|
1596
|
+
"""
|
|
1597
|
+
Recursively group discrete statistics by secondary properties.
|
|
1598
|
+
|
|
1599
|
+
Parameters
|
|
1600
|
+
----------
|
|
1601
|
+
filter_idx : int
|
|
1602
|
+
Index of current secondary property
|
|
1603
|
+
mask : np.ndarray
|
|
1604
|
+
Boolean mask for current group
|
|
1605
|
+
gross_thickness : float
|
|
1606
|
+
Total gross thickness for fraction calculation
|
|
1607
|
+
precision : int, default 6
|
|
1608
|
+
Number of decimal places for rounding
|
|
1609
|
+
|
|
1610
|
+
Returns
|
|
1611
|
+
-------
|
|
1612
|
+
dict
|
|
1613
|
+
Discrete stats dict or nested dict of stats
|
|
1614
|
+
"""
|
|
1615
|
+
if filter_idx >= len(self.secondary_properties):
|
|
1616
|
+
# Base case: compute discrete statistics for this group
|
|
1617
|
+
return self._compute_discrete_stats(mask, gross_thickness, precision)
|
|
1618
|
+
|
|
1619
|
+
# Get unique values for current filter
|
|
1620
|
+
current_filter = self.secondary_properties[filter_idx]
|
|
1621
|
+
current_filter_values = current_filter.values
|
|
1622
|
+
filter_values = current_filter_values[mask]
|
|
1623
|
+
unique_vals = np.unique(filter_values[~np.isnan(filter_values)])
|
|
1624
|
+
|
|
1625
|
+
if len(unique_vals) == 0:
|
|
1626
|
+
# No valid values, return stats for current mask
|
|
1627
|
+
return self._compute_discrete_stats(mask, gross_thickness, precision)
|
|
1628
|
+
|
|
1629
|
+
# Calculate parent thickness for fraction calculation in child groups
|
|
1630
|
+
depth_array = self.depth
|
|
1631
|
+
values_array = self.values
|
|
1632
|
+
parent_intervals = compute_intervals(depth_array)
|
|
1633
|
+
parent_valid = mask & ~np.isnan(values_array)
|
|
1634
|
+
parent_thickness = float(np.sum(parent_intervals[parent_valid]))
|
|
1635
|
+
|
|
1636
|
+
# Group by each unique value
|
|
1637
|
+
result = {}
|
|
1638
|
+
for val in unique_vals:
|
|
1639
|
+
sub_mask = mask & (current_filter_values == val)
|
|
1640
|
+
|
|
1641
|
+
# Create readable key with label if available
|
|
1642
|
+
if current_filter.type == 'discrete':
|
|
1643
|
+
int_val = int(val)
|
|
1644
|
+
else:
|
|
1645
|
+
int_val = int(val) if val == int(val) else None
|
|
1646
|
+
|
|
1647
|
+
if current_filter.labels is not None:
|
|
1648
|
+
if int_val is not None and int_val in current_filter.labels:
|
|
1649
|
+
key = current_filter.labels[int_val]
|
|
1650
|
+
elif val in current_filter.labels:
|
|
1651
|
+
key = current_filter.labels[val]
|
|
1652
|
+
elif int_val is not None:
|
|
1653
|
+
key = f"{current_filter.name}_{int_val}"
|
|
1654
|
+
else:
|
|
1655
|
+
key = f"{current_filter.name}_{val:.2f}"
|
|
1656
|
+
elif int_val is not None:
|
|
1657
|
+
key = f"{current_filter.name}_{int_val}"
|
|
1658
|
+
else:
|
|
1659
|
+
key = f"{current_filter.name}_{val:.2f}"
|
|
1660
|
+
|
|
1661
|
+
result[key] = self._recursive_discrete_group(
|
|
1662
|
+
filter_idx + 1, sub_mask, parent_thickness, precision
|
|
1663
|
+
)
|
|
1664
|
+
|
|
1665
|
+
return result
|
|
1666
|
+
|
|
1667
|
+
def _compute_discrete_stats(
|
|
1668
|
+
self,
|
|
1669
|
+
mask: np.ndarray,
|
|
1670
|
+
gross_thickness: float,
|
|
1671
|
+
precision: int = 6
|
|
1672
|
+
) -> dict:
|
|
1673
|
+
"""
|
|
1674
|
+
Compute categorical statistics for discrete property values.
|
|
1675
|
+
|
|
1676
|
+
Parameters
|
|
1677
|
+
----------
|
|
1678
|
+
mask : np.ndarray
|
|
1679
|
+
Boolean mask selecting subset of data
|
|
1680
|
+
gross_thickness : float
|
|
1681
|
+
Total gross thickness for fraction calculation
|
|
1682
|
+
precision : int, default 6
|
|
1683
|
+
Number of decimal places for rounding
|
|
1684
|
+
|
|
1685
|
+
Returns
|
|
1686
|
+
-------
|
|
1687
|
+
dict
|
|
1688
|
+
Dictionary with stats for each discrete value:
|
|
1689
|
+
{value_label: {code, count, thickness, fraction, depth_range}}
|
|
1690
|
+
"""
|
|
1691
|
+
values_array = self.values
|
|
1692
|
+
depth_array = self.depth
|
|
1693
|
+
|
|
1694
|
+
values = values_array[mask]
|
|
1695
|
+
depths = depth_array[mask]
|
|
1696
|
+
|
|
1697
|
+
# Compute intervals on full array then mask
|
|
1698
|
+
full_intervals = compute_intervals(depth_array)
|
|
1699
|
+
intervals = full_intervals[mask]
|
|
1700
|
+
|
|
1701
|
+
# Find unique discrete values
|
|
1702
|
+
valid_mask_local = ~np.isnan(values)
|
|
1703
|
+
valid_values = values[valid_mask_local]
|
|
1704
|
+
valid_depths = depths[valid_mask_local]
|
|
1705
|
+
valid_intervals = intervals[valid_mask_local]
|
|
1706
|
+
|
|
1707
|
+
if len(valid_values) == 0:
|
|
1708
|
+
return {}
|
|
1709
|
+
|
|
1710
|
+
unique_vals = np.unique(valid_values)
|
|
1711
|
+
|
|
1712
|
+
result = {}
|
|
1713
|
+
for val in unique_vals:
|
|
1714
|
+
val_mask = valid_values == val
|
|
1715
|
+
val_intervals = valid_intervals[val_mask]
|
|
1716
|
+
val_depths = valid_depths[val_mask]
|
|
1717
|
+
|
|
1718
|
+
thickness = float(np.sum(val_intervals))
|
|
1719
|
+
count = int(np.sum(val_mask))
|
|
1720
|
+
fraction = thickness / gross_thickness if gross_thickness > 0 else 0.0
|
|
1721
|
+
|
|
1722
|
+
# Determine the key and label
|
|
1723
|
+
int_val = int(val)
|
|
1724
|
+
if self.labels is not None and int_val in self.labels:
|
|
1725
|
+
key = self.labels[int_val]
|
|
1726
|
+
label = self.labels[int_val]
|
|
1727
|
+
else:
|
|
1728
|
+
key = f"{self.name}_{int_val}"
|
|
1729
|
+
label = None
|
|
1730
|
+
|
|
1731
|
+
stats = {
|
|
1732
|
+
'code': int_val,
|
|
1733
|
+
'count': count,
|
|
1734
|
+
'thickness': round(thickness, precision),
|
|
1735
|
+
'fraction': round(fraction, precision),
|
|
1736
|
+
'depth_range': {
|
|
1737
|
+
'min': round(float(np.min(val_depths)), precision),
|
|
1738
|
+
'max': round(float(np.max(val_depths)), precision)
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
if label is not None:
|
|
1742
|
+
stats['label'] = label
|
|
1743
|
+
|
|
1744
|
+
result[key] = stats
|
|
1745
|
+
|
|
1746
|
+
return result
|
|
1747
|
+
|
|
1523
1748
|
def _recursive_group(
|
|
1524
1749
|
self,
|
|
1525
1750
|
filter_idx: int,
|
|
@@ -14,7 +14,7 @@ import pandas as pd
|
|
|
14
14
|
import matplotlib.pyplot as plt
|
|
15
15
|
import matplotlib.cm as cm
|
|
16
16
|
from matplotlib.collections import PolyCollection
|
|
17
|
-
from matplotlib.colors import Normalize
|
|
17
|
+
from matplotlib.colors import Normalize, LogNorm
|
|
18
18
|
from matplotlib.patches import Rectangle, Patch
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
@@ -2137,6 +2137,20 @@ class WellView:
|
|
|
2137
2137
|
crossover_mask = left_values > right_values
|
|
2138
2138
|
left_values = np.where(crossover_mask, right_values, left_values)
|
|
2139
2139
|
|
|
2140
|
+
# Create valid mask - skip points where boundary values are NaN
|
|
2141
|
+
boundary_valid_mask = ~(np.isnan(left_values) | np.isnan(right_values))
|
|
2142
|
+
|
|
2143
|
+
# Filter arrays to only valid points
|
|
2144
|
+
if not np.all(boundary_valid_mask):
|
|
2145
|
+
left_values = left_values[boundary_valid_mask]
|
|
2146
|
+
right_values = right_values[boundary_valid_mask]
|
|
2147
|
+
depth_for_fill = depth_for_fill[boundary_valid_mask]
|
|
2148
|
+
n_points = len(depth_for_fill)
|
|
2149
|
+
|
|
2150
|
+
if n_points < 2:
|
|
2151
|
+
# Not enough valid points to draw fill
|
|
2152
|
+
return
|
|
2153
|
+
|
|
2140
2154
|
# Apply fill
|
|
2141
2155
|
fill_color = fill.get("color", "lightblue")
|
|
2142
2156
|
fill_alpha = fill.get("alpha", 0.3)
|
|
@@ -2171,6 +2185,10 @@ class WellView:
|
|
|
2171
2185
|
warnings.warn("Cannot determine colormap values (no curve specified for left or right)")
|
|
2172
2186
|
return
|
|
2173
2187
|
|
|
2188
|
+
# Apply same boundary mask to colormap values
|
|
2189
|
+
if not np.all(boundary_valid_mask):
|
|
2190
|
+
colormap_values = colormap_values[boundary_valid_mask]
|
|
2191
|
+
|
|
2174
2192
|
# Get color range for normalization
|
|
2175
2193
|
# Check if we have valid values
|
|
2176
2194
|
valid_mask = ~np.isnan(colormap_values)
|
|
@@ -2179,7 +2197,17 @@ class WellView:
|
|
|
2179
2197
|
return
|
|
2180
2198
|
|
|
2181
2199
|
color_range = fill.get("color_range", [np.nanmin(colormap_values), np.nanmax(colormap_values)])
|
|
2182
|
-
|
|
2200
|
+
# Default color_log to track's log_scale setting
|
|
2201
|
+
color_log = fill.get("color_log", track_log_scale)
|
|
2202
|
+
|
|
2203
|
+
# Use LogNorm for log scale colormap, Normalize for linear
|
|
2204
|
+
if color_log:
|
|
2205
|
+
# Ensure positive values for log scale
|
|
2206
|
+
vmin = max(color_range[0], 1e-10)
|
|
2207
|
+
vmax = max(color_range[1], vmin * 10)
|
|
2208
|
+
norm = LogNorm(vmin=vmin, vmax=vmax)
|
|
2209
|
+
else:
|
|
2210
|
+
norm = Normalize(vmin=color_range[0], vmax=color_range[1])
|
|
2183
2211
|
cmap = plt.get_cmap(cmap_name)
|
|
2184
2212
|
|
|
2185
2213
|
# Create horizontal bands - each depth interval gets a color based on the curve value
|
|
@@ -2274,7 +2302,8 @@ class WellView:
|
|
|
2274
2302
|
ax: plt.Axes,
|
|
2275
2303
|
fill: dict,
|
|
2276
2304
|
plotted_curves: dict,
|
|
2277
|
-
depth: np.ndarray
|
|
2305
|
+
depth: np.ndarray,
|
|
2306
|
+
track_log_scale: bool = False
|
|
2278
2307
|
) -> None:
|
|
2279
2308
|
"""
|
|
2280
2309
|
Add fill between curves or values.
|
|
@@ -2349,6 +2378,20 @@ class WellView:
|
|
|
2349
2378
|
crossover_mask = left_values > right_values
|
|
2350
2379
|
left_values = np.where(crossover_mask, right_values, left_values)
|
|
2351
2380
|
|
|
2381
|
+
# Create valid mask - skip points where boundary values are NaN
|
|
2382
|
+
boundary_valid_mask = ~(np.isnan(left_values) | np.isnan(right_values))
|
|
2383
|
+
|
|
2384
|
+
# Filter arrays to only valid points
|
|
2385
|
+
depth_for_fill = depth # Use local variable for consistency
|
|
2386
|
+
if not np.all(boundary_valid_mask):
|
|
2387
|
+
left_values = left_values[boundary_valid_mask]
|
|
2388
|
+
right_values = right_values[boundary_valid_mask]
|
|
2389
|
+
depth_for_fill = depth[boundary_valid_mask]
|
|
2390
|
+
|
|
2391
|
+
if len(depth_for_fill) < 2:
|
|
2392
|
+
# Not enough valid points to draw fill
|
|
2393
|
+
return
|
|
2394
|
+
|
|
2352
2395
|
# Apply fill
|
|
2353
2396
|
fill_color = fill.get("color", "lightblue")
|
|
2354
2397
|
fill_alpha = fill.get("alpha", 0.3)
|
|
@@ -2383,6 +2426,10 @@ class WellView:
|
|
|
2383
2426
|
warnings.warn("Cannot determine colormap values (no curve specified for left or right)")
|
|
2384
2427
|
return
|
|
2385
2428
|
|
|
2429
|
+
# Apply same boundary mask to colormap values
|
|
2430
|
+
if not np.all(boundary_valid_mask):
|
|
2431
|
+
colormap_values = colormap_values[boundary_valid_mask]
|
|
2432
|
+
|
|
2386
2433
|
# Get color range for normalization
|
|
2387
2434
|
# Check if we have valid values
|
|
2388
2435
|
valid_mask = ~np.isnan(colormap_values)
|
|
@@ -2391,12 +2438,22 @@ class WellView:
|
|
|
2391
2438
|
return
|
|
2392
2439
|
|
|
2393
2440
|
color_range = fill.get("color_range", [np.nanmin(colormap_values), np.nanmax(colormap_values)])
|
|
2394
|
-
|
|
2441
|
+
# Default color_log to track's log_scale setting
|
|
2442
|
+
color_log = fill.get("color_log", track_log_scale)
|
|
2443
|
+
|
|
2444
|
+
# Use LogNorm for log scale colormap, Normalize for linear
|
|
2445
|
+
if color_log:
|
|
2446
|
+
# Ensure positive values for log scale
|
|
2447
|
+
vmin = max(color_range[0], 1e-10)
|
|
2448
|
+
vmax = max(color_range[1], vmin * 10)
|
|
2449
|
+
norm = LogNorm(vmin=vmin, vmax=vmax)
|
|
2450
|
+
else:
|
|
2451
|
+
norm = Normalize(vmin=color_range[0], vmax=color_range[1])
|
|
2395
2452
|
cmap = plt.get_cmap(cmap_name)
|
|
2396
2453
|
|
|
2397
2454
|
# Create horizontal bands - each depth interval gets a color based on the curve value
|
|
2398
2455
|
# Use PolyCollection for performance (1000x faster than loop with fill_betweenx)
|
|
2399
|
-
n_intervals = len(
|
|
2456
|
+
n_intervals = len(depth_for_fill) - 1
|
|
2400
2457
|
|
|
2401
2458
|
# Compute color values for each interval (average of adjacent points)
|
|
2402
2459
|
color_values = (colormap_values[:-1] + colormap_values[1:]) / 2
|
|
@@ -2407,10 +2464,10 @@ class WellView:
|
|
|
2407
2464
|
verts = []
|
|
2408
2465
|
for i in range(n_intervals):
|
|
2409
2466
|
verts.append([
|
|
2410
|
-
(left_values[i],
|
|
2411
|
-
(right_values[i],
|
|
2412
|
-
(right_values[i+1],
|
|
2413
|
-
(left_values[i+1],
|
|
2467
|
+
(left_values[i], depth_for_fill[i]),
|
|
2468
|
+
(right_values[i], depth_for_fill[i]),
|
|
2469
|
+
(right_values[i+1], depth_for_fill[i+1]),
|
|
2470
|
+
(left_values[i+1], depth_for_fill[i+1])
|
|
2414
2471
|
])
|
|
2415
2472
|
|
|
2416
2473
|
# Create PolyCollection with all polygons at once
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/requires.txt
RENAMED
|
File without changes
|
{well_log_toolkit-0.1.139 → well_log_toolkit-0.1.141}/well_log_toolkit.egg-info/top_level.txt
RENAMED
|
File without changes
|