xslope 0.1.10__py3-none-any.whl → 0.1.12__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.
xslope/plot_fem.py CHANGED
@@ -22,8 +22,8 @@ from matplotlib.colors import LinearSegmentedColormap
22
22
  from matplotlib.patches import Polygon
23
23
 
24
24
 
25
- def plot_fem_data(fem_data, figsize=(14, 6), show_nodes=False, show_bc=True, material_table=False,
26
- label_elements=False, label_nodes=False, alpha=0.4, bc_symbol_size=0.03):
25
+ def plot_fem_data(fem_data, figsize=(14, 6), show_nodes=False, show_bc=True,
26
+ label_elements=False, label_nodes=False, alpha=0.4, bc_symbol_size=0.03, save_png=False, dpi=300):
27
27
  """
28
28
  Plots a FEM mesh colored by material zone with boundary conditions displayed.
29
29
 
@@ -32,7 +32,6 @@ def plot_fem_data(fem_data, figsize=(14, 6), show_nodes=False, show_bc=True, mat
32
32
  figsize: Figure size
33
33
  show_nodes: If True, plot node points
34
34
  show_bc: If True, plot boundary condition symbols
35
- material_table: If True, show material table
36
35
  label_elements: If True, label each element with its number at its centroid
37
36
  label_nodes: If True, label each node with its number just above and to the right
38
37
  alpha: Transparency for element faces
@@ -245,12 +244,13 @@ def plot_fem_data(fem_data, figsize=(14, 6), show_nodes=False, show_bc=True, mat
245
244
  else:
246
245
  title = f"FEM Mesh with Material Zones ({num_triangles} triangles)"
247
246
 
248
- # Place the table in the upper left
249
- if material_table:
250
- _plot_fem_material_table(ax, fem_data, xloc=0.3, yloc=1.1) # upper left
251
-
252
247
  ax.set_title(title)
253
248
  plt.tight_layout()
249
+
250
+ if save_png:
251
+ filename = 'plot_' + title.lower().replace(' ', '_').replace(':', '').replace(',', '').replace('(', '').replace(')', '') + '.png'
252
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
253
+
254
254
  plt.show()
255
255
 
256
256
 
@@ -361,73 +361,10 @@ def _plot_boundary_conditions(ax, nodes, bc_type, bc_values, legend_handles, bc_
361
361
  markersize=8, label='Applied Force (bc_type=4)')
362
362
  )
363
363
 
364
-
365
- def _plot_fem_material_table(ax, fem_data, xloc=0.6, yloc=0.7):
366
- """
367
- Adds a FEM material properties table to the plot.
368
-
369
- Parameters:
370
- ax: matplotlib Axes object
371
- fem_data: Dictionary containing FEM data with material properties
372
- xloc: x-location of table (0-1)
373
- yloc: y-location of table (0-1)
374
-
375
- Returns:
376
- None
377
- """
378
- # Extract material properties from fem_data
379
- c_by_mat = fem_data.get("c_by_mat")
380
- phi_by_mat = fem_data.get("phi_by_mat")
381
- E_by_mat = fem_data.get("E_by_mat")
382
- nu_by_mat = fem_data.get("nu_by_mat")
383
- gamma_by_mat = fem_data.get("gamma_by_mat")
384
- material_names = fem_data.get("material_names", [])
385
-
386
- if c_by_mat is None or len(c_by_mat) == 0:
387
- return
388
-
389
- # Column headers for FEM properties
390
- col_labels = ["Mat", "Name", "γ", "c", "φ", "E", "ν"]
391
-
392
- # Build table rows
393
- table_data = []
394
- for idx in range(len(c_by_mat)):
395
- c = c_by_mat[idx]
396
- phi = phi_by_mat[idx] if phi_by_mat is not None else 0.0
397
- E = E_by_mat[idx] if E_by_mat is not None else 0.0
398
- nu = nu_by_mat[idx] if nu_by_mat is not None else 0.0
399
- gamma = gamma_by_mat[idx] if gamma_by_mat is not None else 0.0
400
-
401
- # Get material name, use default if not available
402
- material_name = material_names[idx] if idx < len(material_names) else f"Material {idx+1}"
403
-
404
- # Format values with appropriate precision
405
- row = [
406
- idx + 1, # Material number (1-based)
407
- material_name, # Material name
408
- f"{gamma:.1f}", # unit weight
409
- f"{c:.1f}", # cohesion
410
- f"{phi:.1f}", # friction angle
411
- f"{E:.0f}", # Young's modulus
412
- f"{nu:.2f}" # Poisson's ratio
413
- ]
414
- table_data.append(row)
415
-
416
- # Add the table
417
- table = ax.table(cellText=table_data,
418
- colLabels=col_labels,
419
- loc='upper right',
420
- colLoc='center',
421
- cellLoc='center',
422
- bbox=[xloc, yloc, 0.45, 0.25]) # Increased width to accommodate name column
423
- table.auto_set_font_size(False)
424
- table.set_fontsize(8)
425
-
426
-
427
364
  def plot_fem_results(fem_data, solution, plot_type='displacement', deform_scale=None,
428
365
  show_mesh=True, show_reinforcement=True, figsize=(12, 8), label_elements=False,
429
366
  plot_nodes=False, plot_elements=False, plot_boundary=True, displacement_tolerance=0.5,
430
- scale_vectors=False):
367
+ scale_vectors=False, save_png=False, dpi=300):
431
368
  """
432
369
  Plot FEM results with various visualization options.
433
370
 
@@ -540,6 +477,11 @@ def plot_fem_results(fem_data, solution, plot_type='displacement', deform_scale=
540
477
  ax.set_aspect('equal')
541
478
 
542
479
  plt.tight_layout()
480
+
481
+ if save_png:
482
+ filename = f'plot_fem_results_{plot_type.lower().replace(",", "_").replace(" ", "_")}.png'
483
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
484
+
543
485
  plt.show()
544
486
 
545
487
  # Return appropriate values
@@ -1071,7 +1013,7 @@ def plot_reinforcement_forces(ax, fem_data, solution):
1071
1013
  ax.add_collection(lc_failed)
1072
1014
 
1073
1015
 
1074
- def plot_reinforcement_force_profiles(fem_data, solution, figsize=(12, 8)):
1016
+ def plot_reinforcement_force_profiles(fem_data, solution, figsize=(12, 8), save_png=False, dpi=300):
1075
1017
  """
1076
1018
  Plot force profiles along each reinforcement line.
1077
1019
  """
@@ -1170,10 +1112,15 @@ def plot_reinforcement_force_profiles(fem_data, solution, figsize=(12, 8)):
1170
1112
  axes[i].set_visible(False)
1171
1113
 
1172
1114
  plt.tight_layout()
1115
+
1116
+ if save_png:
1117
+ filename = 'plot_reinforcement_force_profiles.png'
1118
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
1119
+
1173
1120
  return fig, axes
1174
1121
 
1175
1122
 
1176
- def plot_ssrm_convergence(ssrm_solution, figsize=(10, 6)):
1123
+ def plot_ssrm_convergence(ssrm_solution, figsize=(10, 6), save_png=False, dpi=300):
1177
1124
  """
1178
1125
  Plot SSRM convergence history.
1179
1126
  """
@@ -1214,6 +1161,11 @@ def plot_ssrm_convergence(ssrm_solution, figsize=(10, 6)):
1214
1161
  ax2.grid(True, alpha=0.3)
1215
1162
 
1216
1163
  plt.tight_layout()
1164
+
1165
+ if save_png:
1166
+ filename = 'plot_ssrm_convergence.png'
1167
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
1168
+
1217
1169
  return fig, (ax1, ax2)
1218
1170
 
1219
1171
 
xslope/plot_seep.py CHANGED
@@ -4,7 +4,7 @@ from matplotlib.ticker import MaxNLocator
4
4
  import numpy as np
5
5
 
6
6
 
7
- def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False, material_table=False, label_elements=False, label_nodes=False, alpha=0.4):
7
+ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False, label_elements=False, label_nodes=False, alpha=0.4, save_png=False, dpi=300):
8
8
  """
9
9
  Plots a mesh colored by material zone.
10
10
  Supports both triangular and quadrilateral elements.
@@ -13,7 +13,6 @@ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False,
13
13
  seep_data: Dictionary containing seepage data from import_seep2d
14
14
  show_nodes: If True, plot node points
15
15
  show_bc: If True, plot boundary condition nodes
16
- material_table: If True, show material table
17
16
  label_elements: If True, label each element with its number at its centroid
18
17
  label_nodes: If True, label each node with its number just above and to the right
19
18
  """
@@ -181,10 +180,10 @@ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False,
181
180
  bc1 = nodes[bc_type == 1]
182
181
  bc2 = nodes[bc_type == 2]
183
182
  if len(bc1) > 0:
184
- h1, = ax.plot(bc1[:, 0], bc1[:, 1], 'ro', label="Fixed Head (bc_type=1)")
183
+ h1, = ax.plot(bc1[:, 0], bc1[:, 1], 'bs', label="Fixed Head (bc_type=1)")
185
184
  legend_handles.append(h1)
186
185
  if len(bc2) > 0:
187
- h2, = ax.plot(bc2[:, 0], bc2[:, 1], 'bs', label="Exit Face (bc_type=2)")
186
+ h2, = ax.plot(bc2[:, 0], bc2[:, 1], 'ro', label="Exit Face (bc_type=2)")
188
187
  legend_handles.append(h2)
189
188
 
190
189
  # Single combined legend outside the plot
@@ -196,6 +195,12 @@ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False,
196
195
  frameon=False
197
196
  )
198
197
  ax.set_aspect("equal")
198
+
199
+ # Add a bit of headroom so the mesh/BC markers don't touch the top border
200
+ y0, y1 = ax.get_ylim()
201
+ if y1 > y0:
202
+ pad = 0.05 * (y1 - y0)
203
+ ax.set_ylim(y0, y1 + pad)
199
204
 
200
205
  # Count element types for title
201
206
  num_triangles = np.sum(element_types == 3)
@@ -207,17 +212,18 @@ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False,
207
212
  else:
208
213
  title = f"SEEP2D Mesh with Material Zones ({num_triangles} triangles)"
209
214
 
210
- # Place the table in the upper left
211
- if material_table:
212
- plot_seep_material_table(ax, seep_data, xloc=0.3, yloc=1.1) # upper left
213
-
214
215
  ax.set_title(title)
215
216
  # plt.subplots_adjust(bottom=0.2) # Add vertical cushion
216
217
  plt.tight_layout()
218
+
219
+ if save_png:
220
+ filename = 'plot_' + title.lower().replace(' ', '_').replace(':', '').replace(',', '').replace('(', '').replace(')', '') + '.png'
221
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
222
+
217
223
  plt.show()
218
224
 
219
225
 
220
- def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat=1, fill_contours=True, phreatic=True, alpha=0.4, pad_frac=0.05, mesh=True, variable="head", vectors=False, vector_scale=0.05, flowlines=True):
226
+ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat=1, fill_contours=True, phreatic=True, alpha=0.4, pad_frac=0.05, mesh=True, variable="head", vectors=False, vector_scale=0.05, flowlines=True, save_png=False, dpi=300):
221
227
  """
222
228
  Plot seepage analysis results including head contours, flowlines, and phreatic surface.
223
229
 
@@ -579,69 +585,15 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
579
585
  # Remove tight_layout and subplots_adjust for best constrained layout
580
586
  # plt.tight_layout()
581
587
  # plt.subplots_adjust(top=0.78)
588
+
589
+ if save_png:
590
+ filename = 'plot_' + title.lower().replace(' ', '_').replace(':', '').replace(',', '').replace('—', '').replace('(', '').replace(')', '') + '.png'
591
+ plt.savefig(filename, dpi=dpi, bbox_inches='tight')
592
+
582
593
  plt.show()
583
594
 
584
595
 
585
- def plot_seep_material_table(ax, seep_data, xloc=0.6, yloc=0.7):
586
- """
587
- Adds a seepage material properties table to the plot.
588
-
589
- Parameters:
590
- ax: matplotlib Axes object
591
- seep_data: Dictionary containing seepage data with material properties
592
- xloc: x-location of table (0-1)
593
- yloc: y-location of table (0-1)
594
-
595
- Returns:
596
- None
597
- """
598
- # Extract material properties from seep_data
599
- k1_by_mat = seep_data.get("k1_by_mat")
600
- k2_by_mat = seep_data.get("k2_by_mat")
601
- angle_by_mat = seep_data.get("angle_by_mat")
602
- kr0_by_mat = seep_data.get("kr0_by_mat")
603
- h0_by_mat = seep_data.get("h0_by_mat")
604
- material_names = seep_data.get("material_names", [])
605
-
606
- if k1_by_mat is None or len(k1_by_mat) == 0:
607
- return
608
-
609
- # Column headers for seepage properties
610
- col_labels = ["Mat", "Name", "k₁", "k₂", "Angle", "kr₀", "h₀"]
611
-
612
- # Build table rows
613
- table_data = []
614
- for idx in range(len(k1_by_mat)):
615
- k1 = k1_by_mat[idx]
616
- k2 = k2_by_mat[idx] if k2_by_mat is not None else 0.0
617
- angle = angle_by_mat[idx] if angle_by_mat is not None else 0.0
618
- kr0 = kr0_by_mat[idx] if kr0_by_mat is not None else 0.0
619
- h0 = h0_by_mat[idx] if h0_by_mat is not None else 0.0
620
-
621
- # Get material name, use default if not available
622
- material_name = material_names[idx] if idx < len(material_names) else f"Material {idx+1}"
623
-
624
- # Format values with appropriate precision
625
- row = [
626
- idx + 1, # Material number (1-based)
627
- material_name, # Material name
628
- f"{k1:.3f}", # k1 in scientific notation
629
- f"{k2:.3f}", # k2 in scientific notation
630
- f"{angle:.1f}", # angle in degrees
631
- f"{kr0:.4f}", # kr0
632
- f"{h0:.2f}" # h0
633
- ]
634
- table_data.append(row)
635
-
636
- # Add the table
637
- table = ax.table(cellText=table_data,
638
- colLabels=col_labels,
639
- loc='upper right',
640
- colLoc='center',
641
- cellLoc='center',
642
- bbox=[xloc, yloc, 0.45, 0.25]) # Increased width to accommodate name column
643
- table.auto_set_font_size(False)
644
- table.set_fontsize(8)
596
+ # plot_seep_material_table has been moved to xslope/plot.py
645
597
 
646
598
 
647
599
  def get_ordered_mesh_boundary(nodes, elements, element_types=None):
xslope/seep.py CHANGED
@@ -404,7 +404,7 @@ def solve_confined(nodes, elements, bc_type, dirichlet_bcs, k1_vals, k2_vals, an
404
404
 
405
405
  def solve_unsaturated(nodes, elements, bc_type, bc_values, kr0=0.001, h0=-1.0,
406
406
  k1_vals=1.0, k2_vals=1.0, angles=0.0,
407
- max_iter=200, tol=1e-4, element_types=None):
407
+ max_iter=200, tol=1e-6, element_types=None):
408
408
  """
409
409
  Iterative FEM solver for unconfined flow using linear kr frontal function.
410
410
  Supports triangular and quadrilateral elements with both linear and quadratic shape functions.
@@ -716,7 +716,7 @@ def solve_unsaturated(nodes, elements, bc_type, bc_values, kr0=0.001, h0=-1.0,
716
716
  print(" - Non-conservative flow field")
717
717
  print(" - Incorrect boundary identification")
718
718
  print(" - Numerical issues in the flow solution")
719
-
719
+ print(f"Try reducing the tolerance (tol) parameter. Current value: {tol:.6e}")
720
720
 
721
721
  return h, A, q_final, total_inflow
722
722
 
@@ -969,10 +969,14 @@ def create_flow_potential_bc(nodes, elements, q, debug=False, element_types=None
969
969
  starting_phi = phi[ordered_nodes[start_idx]]
970
970
  closure_error = phi_val - starting_phi
971
971
 
972
- if debug or abs(closure_error) > 1e-3:
972
+ # Use a relative threshold based on total positive boundary flow
973
+ rel_tol = 1e-2 # 1%
974
+ scale = max(total_q, 1e-12)
975
+
976
+ if debug or abs(closure_error) > rel_tol * scale:
973
977
  print(f"Flow potential closure check: error = {closure_error:.6e}")
974
978
 
975
- if abs(closure_error) > 1e-3:
979
+ if abs(closure_error) > rel_tol * scale:
976
980
  print(f"Warning: Large flow potential closure error = {closure_error:.6e}")
977
981
  print("This may indicate:")
978
982
  print(" - Non-conservative flow field")
@@ -1983,7 +1987,7 @@ def quad4_stiffness_matrix(nodes_elem, Kmat):
1983
1987
 
1984
1988
  return ke
1985
1989
 
1986
- def run_seepage_analysis(seep_data):
1990
+ def run_seepage_analysis(seep_data, tol=1e-6):
1987
1991
  """
1988
1992
  Standalone function to run seepage analysis.
1989
1993
 
@@ -2048,7 +2052,8 @@ def run_seepage_analysis(seep_data):
2048
2052
  k1_vals=k1,
2049
2053
  k2_vals=k2,
2050
2054
  angles=angle,
2051
- element_types=element_types
2055
+ element_types=element_types,
2056
+ tol=tol
2052
2057
  )
2053
2058
  # Solve for potential function φ for flow lines
2054
2059
  dirichlet_phi_bcs = create_flow_potential_bc(nodes, elements, q, element_types=element_types)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xslope
3
- Version: 0.1.10
3
+ Version: 0.1.12
4
4
  Summary: Slope stability analysis (limit equilibrium and FEM) in Python.
5
5
  Author: Norman L. Jones
6
6
  Project-URL: Homepage, https://github.com/njones61/xslope
@@ -0,0 +1,21 @@
1
+ xslope/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
+ xslope/_version.py,sha256=q5MF9vedBklo3vj52_gwvihlwfAGwilLmjxYlgKI-zM,51
3
+ xslope/advanced.py,sha256=35k_ekQJ-mQJ1wHnoIHMc5TVfYn-2EPCJyHz827Cpbc,18281
4
+ xslope/fem.py,sha256=K4_Pq06HFBpRkN3JwtXF2zw_AMnCkXvj0ggrlRFMQQw,115731
5
+ xslope/fileio.py,sha256=nxpD5dnkWjSVnby9jsQgHrxikfAsL3KOUehiw8sMb-Q,31783
6
+ xslope/global_config.py,sha256=Cj8mbPidIuj5Ty-5cZM-c8H12kNvyHsk5_ofNGez-3M,2253
7
+ xslope/mesh copy.py,sha256=qtMH1yKFgHM4kNuIrxco7tKV86R3Dbf7Nok5j6MtlLY,131013
8
+ xslope/mesh.py,sha256=dY_G7ctgOroUSv2oUuM-ZQOnKAEJ1dIq6FTU_JLWEqs,136816
9
+ xslope/plot.py,sha256=SuwC6quvkdQ66sVzSam3USRoEUC99s-iS1_0j-V7k8A,81401
10
+ xslope/plot_fem.py,sha256=z2FLPbIx6yNIKYcgC-LcZz2jfx0WLYFL3xJgNvQ1t-c,69488
11
+ xslope/plot_seep.py,sha256=wEmK3FCYjkqtnNqy1nhFLe72GBVrdhcR0CkgxlLaAjc,32948
12
+ xslope/search.py,sha256=dvgKn8JCobuvyD7fClF5lcbeHESCvV8gZ_U_lQnYRok,16867
13
+ xslope/seep.py,sha256=Xc3C3HcAOXBdsVStJTPo2AxY4QjQKjMcfTuJGYCazMY,93300
14
+ xslope/slice.py,sha256=QHawTk7XPLziHoN_ZS0jrEPYKlhPT62caUc_q-_EGjs,45236
15
+ xslope/solve.py,sha256=u_sBjtsj1EeZtgSEmo80tEWoRrrMgvRjmi6P0ODO1lU,48645
16
+ xslope-0.1.12.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
17
+ xslope-0.1.12.dist-info/METADATA,sha256=BPz97uzKVuFiS9_RqS5r6iYd4O0W4IacO-CyZEsUaHY,2028
18
+ xslope-0.1.12.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
19
+ xslope-0.1.12.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
20
+ xslope-0.1.12.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
21
+ xslope-0.1.12.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- xslope/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
- xslope/_version.py,sha256=DfeCqc-dgdypmy58WabEWmjpVnqKiY50hCCECclU5_I,51
3
- xslope/advanced.py,sha256=35k_ekQJ-mQJ1wHnoIHMc5TVfYn-2EPCJyHz827Cpbc,18281
4
- xslope/fem.py,sha256=K4_Pq06HFBpRkN3JwtXF2zw_AMnCkXvj0ggrlRFMQQw,115731
5
- xslope/fileio.py,sha256=DnFUYmJedjKXOuVPZUfTRxGfTjiIz8KyHkRDK7ddQg0,28840
6
- xslope/global_config.py,sha256=Cj8mbPidIuj5Ty-5cZM-c8H12kNvyHsk5_ofNGez-3M,2253
7
- xslope/mesh copy.py,sha256=qtMH1yKFgHM4kNuIrxco7tKV86R3Dbf7Nok5j6MtlLY,131013
8
- xslope/mesh.py,sha256=qtMH1yKFgHM4kNuIrxco7tKV86R3Dbf7Nok5j6MtlLY,131013
9
- xslope/plot.py,sha256=OW2eZyrT5h3Y95qjNFgGMnC_Am7TurUB2S7b_BgnO6E,54641
10
- xslope/plot_fem.py,sha256=al9zjqjxWKooLl4SAds77Zz-j9cjD4TJGygyU9QK5vo,71111
11
- xslope/plot_seep.py,sha256=Fs8S-0_7bnNJZlj7SnM0ij1mFDZWlNjXGnP6iMDiplY,34647
12
- xslope/search.py,sha256=dvgKn8JCobuvyD7fClF5lcbeHESCvV8gZ_U_lQnYRok,16867
13
- xslope/seep.py,sha256=tLvme-eL0R5SGGTH2Y6z4Rrfe36UuSWWLlL_1kglee8,93030
14
- xslope/slice.py,sha256=QHawTk7XPLziHoN_ZS0jrEPYKlhPT62caUc_q-_EGjs,45236
15
- xslope/solve.py,sha256=u_sBjtsj1EeZtgSEmo80tEWoRrrMgvRjmi6P0ODO1lU,48645
16
- xslope-0.1.10.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
17
- xslope-0.1.10.dist-info/METADATA,sha256=-iSQGoUnwIJgNg0sZizK2iZk6JRVarH5mDMpUxsFSgI,2028
18
- xslope-0.1.10.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
19
- xslope-0.1.10.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
20
- xslope-0.1.10.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
21
- xslope-0.1.10.dist-info/RECORD,,