xslope 0.1.7__py3-none-any.whl → 0.1.9__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/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.1.7"
2
+ __version__ = "0.1.9"
3
3
 
4
4
 
xslope/plot_seep.py CHANGED
@@ -217,20 +217,73 @@ def plot_seep_data(seep_data, figsize=(14, 6), show_nodes=False, show_bc=False,
217
217
  plt.show()
218
218
 
219
219
 
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, show_mesh=True):
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):
221
221
  """
222
- Plots head contours and optionally overlays flowlines (phi) based on flow function.
223
- Fixed version that properly handles mesh aspect ratio and doesn't clip the plot.
224
- Supports both triangular and quadrilateral elements.
225
-
226
- Arguments:
227
- seep_data: Dictionary containing seepage data from import_seep2d
228
- solution: Dictionary containing solution results from run_analysis
229
- levels: number of head contour levels
230
- base_mat: material ID (1-based) used to compute k for flow function
231
- fill_contours: bool, if True shows filled contours, if False only black solid lines
232
- phreatic: bool, if True plots phreatic surface (pressure head = 0) as thick red line
233
- show_mesh: bool, if True overlays element edges in light gray
222
+ Plot seepage analysis results including head contours, flowlines, and phreatic surface.
223
+
224
+ This function visualizes the results of a seepage analysis by plotting contours of various
225
+ nodal variables (head, pore pressure, velocity magnitude, or gradient magnitude). When
226
+ plotting head, flowlines are also overlaid. The plot properly handles mesh aspect ratios
227
+ and supports both linear and quadratic triangular and quadrilateral elements.
228
+
229
+ Parameters:
230
+ -----------
231
+ seep_data : dict
232
+ Dictionary containing seepage mesh data from import_seep2d. Required keys include:
233
+ 'nodes', 'elements', 'element_materials', 'element_types' (optional), and
234
+ 'k1_by_mat' (optional, for flowline calculation).
235
+ solution : dict
236
+ Dictionary containing solution results from run_seepage_analysis. Required keys include:
237
+ 'head' (array of total head values at nodes), 'velocity' (array of velocity vectors),
238
+ 'gradient' (array of hydraulic gradient vectors). Optional keys: 'phi' (stream function),
239
+ 'flowrate' (total flow rate), 'u' (pore pressure), 'v_mag' (velocity magnitude),
240
+ 'i_mag' (gradient magnitude).
241
+ figsize : tuple of float, optional
242
+ Figure size in inches (width, height). Default is (14, 6).
243
+ levels : int, optional
244
+ Number of contour levels to plot. Default is 20.
245
+ base_mat : int, optional
246
+ Material ID (1-based) used to compute hydraulic conductivity for flow function
247
+ calculation. Default is 1. Only used when variable="head".
248
+ fill_contours : bool, optional
249
+ If True, shows filled contours with color map. If False, only black solid
250
+ contour lines are shown. Default is True.
251
+ phreatic : bool, optional
252
+ If True, plots the phreatic surface (where pressure head = 0) as a thick red line.
253
+ Default is True. Only plotted if pore pressure is negative somewhere in the domain.
254
+ alpha : float, optional
255
+ Transparency level (0-1) for material zone fill colors. Default is 0.4.
256
+ pad_frac : float, optional
257
+ Fraction of mesh extent to add as padding around the plot boundaries. Default is 0.05.
258
+ mesh : bool, optional
259
+ If True, overlays element edges in light gray. Default is True.
260
+ variable : str, optional
261
+ Nodal variable to contour. Options: "head" (default), "u" (pore pressure),
262
+ "v_mag" (velocity magnitude), "i_mag" (gradient magnitude). When "head" is selected,
263
+ flowlines can be overlaid if flowlines=True. Other variables do not include flowlines.
264
+ vectors : bool, optional
265
+ If True, plots velocity vectors as arrows at each node. Default is False.
266
+ vector_scale : float, optional
267
+ Scale factor for vector lengths. Maximum vector length will be x_range * vector_scale,
268
+ where x_range is the x-extent of the mesh. Default is 0.05.
269
+ flowlines : bool, optional
270
+ If True and variable="head", overlays flowlines (stream function contours) on the plot.
271
+ Default is True. Only applicable when variable="head".
272
+
273
+ Returns:
274
+ --------
275
+ None
276
+ Displays the plot using matplotlib.pyplot.show().
277
+
278
+ Notes:
279
+ ------
280
+ - The function automatically subdivides quadratic elements (tri6, quad8, quad9) for
281
+ proper visualization and contouring.
282
+ - Flowlines are only plotted when variable="head" and if 'phi' and 'flowrate' are present
283
+ in solution and 'k1_by_mat' is present in seep_data.
284
+ - The plot includes a colorbar for contours when fill_contours=True.
285
+ - The title includes flowrate information if available in the solution dictionary and
286
+ variable="head".
234
287
  """
235
288
  import matplotlib.pyplot as plt
236
289
  import matplotlib.tri as tri
@@ -238,15 +291,30 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
238
291
  from matplotlib.patches import Polygon
239
292
  import numpy as np
240
293
 
294
+ # Validate variable parameter
295
+ valid_variables = ["head", "u", "v_mag", "i_mag"]
296
+ if variable not in valid_variables:
297
+ raise ValueError(f"variable must be one of {valid_variables}, got '{variable}'")
298
+
241
299
  # Extract data from seep_data and solution
242
300
  nodes = seep_data["nodes"]
243
301
  elements = seep_data["elements"]
244
302
  element_materials = seep_data["element_materials"]
245
303
  element_types = seep_data.get("element_types", None) # New field for element types
246
304
  k1_by_mat = seep_data.get("k1_by_mat") # Use .get() in case it's not present
305
+
306
+ # Extract the variable to plot
307
+ if variable not in solution:
308
+ raise ValueError(f"Variable '{variable}' not found in solution dictionary. Available keys: {list(solution.keys())}")
309
+ contour_data = solution[variable]
310
+
311
+ # Extract head and flowline-related data (only needed for head plots)
247
312
  head = solution["head"]
248
313
  phi = solution.get("phi")
249
314
  flowrate = solution.get("flowrate")
315
+
316
+ # Determine if we should plot flowlines (only for head and if flowlines=True)
317
+ plot_flowlines = (variable == "head" and flowlines)
250
318
 
251
319
 
252
320
  # Use constrained_layout for best layout
@@ -347,9 +415,9 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
347
415
  for sub_quad in sub_quads:
348
416
  ax.fill(*zip(*sub_quad), edgecolor='none', facecolor=color, alpha=alpha)
349
417
 
350
- vmin = np.min(head)
351
- vmax = np.max(head)
352
- hdrop = vmax - vmin
418
+ # Set up contour levels
419
+ vmin = np.min(contour_data)
420
+ vmax = np.max(contour_data)
353
421
  contour_levels = np.linspace(vmin, vmax, levels)
354
422
 
355
423
  # For contouring, subdivide tri6 elements into 4 subtriangles
@@ -374,24 +442,41 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
374
442
  all_triangles_for_contouring.extend([tri1, tri2])
375
443
  triang = tri.Triangulation(nodes[:, 0], nodes[:, 1], all_triangles_for_contouring)
376
444
 
445
+ # Variable labels for colorbar and title
446
+ variable_labels = {
447
+ "head": "Total Head",
448
+ "u": "Pore Pressure",
449
+ "v_mag": "Velocity Magnitude",
450
+ "i_mag": "Hydraulic Gradient Magnitude"
451
+ }
452
+ variable_label = variable_labels[variable]
453
+
377
454
  # Filled contours (only if fill_contours=True)
378
455
  if fill_contours:
379
- contourf = ax.tricontourf(triang, head, levels=contour_levels, cmap="Spectral_r", vmin=vmin, vmax=vmax, alpha=0.5)
380
- cbar = plt.colorbar(contourf, ax=ax, label="Total Head", shrink=0.8, pad=0.02)
456
+ contourf = ax.tricontourf(triang, contour_data, levels=contour_levels, cmap="Spectral_r", vmin=vmin, vmax=vmax, alpha=0.5)
457
+ cbar = plt.colorbar(contourf, ax=ax, label=variable_label, shrink=0.8, pad=0.02)
381
458
  cbar.locator = MaxNLocator(nbins=10, steps=[1, 2, 5])
382
459
  cbar.update_ticks()
383
460
 
384
- # Solid lines for head contours
385
- ax.tricontour(triang, head, levels=contour_levels, colors="k", linewidths=0.5)
461
+ # Solid lines for contours
462
+ ax.tricontour(triang, contour_data, levels=contour_levels, colors="k", linewidths=0.5)
386
463
 
387
464
  # Phreatic surface (pressure head = 0)
465
+ # Check if phreatic surface exists (pore pressure must be negative somewhere)
466
+ has_phreatic = False
388
467
  if phreatic:
389
- elevation = nodes[:, 1] # y-coordinate is elevation
390
- pressure_head = head - elevation
391
- ax.tricontour(triang, pressure_head, levels=[0], colors="red", linewidths=2.0)
392
-
393
- # Overlay flowlines if phi is available
394
- if phi is not None and flowrate is not None and k1_by_mat is not None:
468
+ # Check if pore pressure goes negative (indicating a phreatic surface exists)
469
+ u = solution.get("u")
470
+ if u is not None and np.min(u) < 0:
471
+ elevation = nodes[:, 1] # y-coordinate is elevation
472
+ pressure_head = head - elevation
473
+ ax.tricontour(triang, pressure_head, levels=[0], colors="black", linewidths=2.0)
474
+ has_phreatic = True
475
+
476
+ # Overlay flowlines if variable is head and phi is available
477
+ if plot_flowlines and phi is not None and flowrate is not None and k1_by_mat is not None:
478
+ # Compute head drop for flowline calculation
479
+ hdrop = vmax - vmin
395
480
  if base_mat > len(k1_by_mat):
396
481
  print(f"Warning: base_mat={base_mat} is larger than number of materials ({len(k1_by_mat)}). Using material 1.")
397
482
  base_mat = 1
@@ -406,8 +491,39 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
406
491
  phi_contours = np.linspace(np.min(phi), np.max(phi), phi_levels)
407
492
  ax.tricontour(triang, phi, levels=phi_contours, colors="blue", linewidths=0.7, linestyles="solid")
408
493
 
494
+ # Plot velocity vectors if requested
495
+ if vectors:
496
+ velocity = solution.get("velocity")
497
+ if velocity is not None:
498
+ # Calculate x_range for scaling
499
+ x_min_vec = nodes[:, 0].min()
500
+ x_max_vec = nodes[:, 0].max()
501
+ x_range = x_max_vec - x_min_vec
502
+ max_vector_length = x_range * vector_scale
503
+
504
+ # Get velocity magnitude
505
+ v_mag = solution.get("v_mag")
506
+ if v_mag is None:
507
+ # Calculate v_mag if not available
508
+ v_mag = np.linalg.norm(velocity, axis=1)
509
+
510
+ # Find maximum velocity magnitude
511
+ max_v_mag = np.max(v_mag)
512
+
513
+ # Scale vectors: if max_v_mag > 0, scale so max vector has length max_vector_length
514
+ if max_v_mag > 0:
515
+ scale_factor = max_vector_length / max_v_mag
516
+ velocity_scaled = velocity * scale_factor
517
+ else:
518
+ velocity_scaled = velocity
519
+
520
+ # Plot vectors using quiver
521
+ ax.quiver(nodes[:, 0], nodes[:, 1], velocity_scaled[:, 0], velocity_scaled[:, 1],
522
+ angles='xy', scale_units='xy', scale=1, width=0.002, headwidth=2.5,
523
+ headlength=3, headaxislength=2.5, color='black', alpha=0.7)
524
+
409
525
  # Plot element edges if requested
410
- if show_mesh:
526
+ if mesh:
411
527
  # Draw all element edges
412
528
  for element, elem_type in zip(elements, element_types if element_types is not None else [3]*len(elements)):
413
529
  if elem_type == 3:
@@ -444,13 +560,17 @@ def plot_seep_solution(seep_data, solution, figsize=(14, 6), levels=20, base_mat
444
560
  ax.set_xlim(x_min - x_pad, x_max + x_pad)
445
561
  ax.set_ylim(y_min - y_pad, y_max + y_pad)
446
562
 
447
- title = "Flow Net: Head Contours"
448
- if phi is not None:
449
- title += " and Flowlines"
450
- if phreatic:
451
- title += " with Phreatic Surface"
452
- if flowrate is not None:
453
- title += f" Total Flowrate: {flowrate:.3f}"
563
+ # Build title based on variable
564
+ if variable == "head":
565
+ title = f"Flow Net: {variable_label} Contours"
566
+ if plot_flowlines and phi is not None:
567
+ title += " and Flowlines"
568
+ if has_phreatic:
569
+ title += " with Phreatic Surface"
570
+ if flowrate is not None:
571
+ title += f" — Total Flowrate: {flowrate:.3f}"
572
+ else:
573
+ title = f"{variable_label} Contours"
454
574
  ax.set_title(title)
455
575
 
456
576
  # Set equal aspect ratio AFTER setting limits
xslope/seep.py CHANGED
@@ -1515,6 +1515,142 @@ def compute_velocity(nodes, elements, head, k1_vals, k2_vals, angles, kr0=None,
1515
1515
  velocity /= count[:, None]
1516
1516
  return velocity
1517
1517
 
1518
+ def compute_gradient(nodes, elements, head, element_types=None):
1519
+ """
1520
+ Compute nodal hydraulic gradient by averaging element-wise head gradients.
1521
+ The hydraulic gradient i = -grad(h), where grad(h) is the gradient of head.
1522
+ Supports both triangular and quadrilateral elements.
1523
+
1524
+ Parameters:
1525
+ nodes : (n_nodes, 2) array of node coordinates
1526
+ elements : (n_elements, 3 or 4) triangle or quad node indices
1527
+ head : (n_nodes,) nodal head solution
1528
+ element_types : (n_elements,) array indicating 3 for triangles, 4 for quads
1529
+
1530
+ Returns:
1531
+ gradient : (n_nodes, 2) array of nodal hydraulic gradient vectors [ix, iy]
1532
+ """
1533
+ # If element_types is not provided, assume all triangles (backward compatibility)
1534
+ if element_types is None:
1535
+ element_types = np.full(len(elements), 3)
1536
+
1537
+ n_nodes = nodes.shape[0]
1538
+ gradient = np.zeros((n_nodes, 2))
1539
+ count = np.zeros(n_nodes)
1540
+
1541
+ for idx, element_nodes in enumerate(elements):
1542
+ element_type = element_types[idx]
1543
+
1544
+ if element_type == 3:
1545
+ # Triangle: use first 3 nodes
1546
+ i, j, k = element_nodes[:3]
1547
+ xi, yi = nodes[i]
1548
+ xj, yj = nodes[j]
1549
+ xk, yk = nodes[k]
1550
+
1551
+ area = 0.5 * np.linalg.det([[1, xi, yi], [1, xj, yj], [1, xk, yk]])
1552
+ if area <= 0:
1553
+ continue
1554
+
1555
+ beta = np.array([yj - yk, yk - yi, yi - yj])
1556
+ gamma = np.array([xk - xj, xi - xk, xj - xi])
1557
+ grad = np.array([beta, gamma]) / (2 * area)
1558
+
1559
+ h_vals = head[[i, j, k]]
1560
+ grad_h = grad @ h_vals
1561
+ # Hydraulic gradient i = -grad(h)
1562
+ i_elem = -grad_h
1563
+
1564
+ for node in element_nodes[:3]:
1565
+ gradient[node] += i_elem
1566
+ count[node] += 1
1567
+ elif element_type == 4:
1568
+ # Quadrilateral: use first 4 nodes
1569
+ i, j, k, l = element_nodes[:4]
1570
+ nodes_elem = nodes[[i, j, k, l], :]
1571
+ h_elem = head[[i, j, k, l]]
1572
+
1573
+ # 2x2 Gauss points and weights
1574
+ gauss_pts = [(-1/np.sqrt(3), -1/np.sqrt(3)),
1575
+ (1/np.sqrt(3), -1/np.sqrt(3)),
1576
+ (1/np.sqrt(3), 1/np.sqrt(3)),
1577
+ (-1/np.sqrt(3), 1/np.sqrt(3))]
1578
+
1579
+ for (xi, eta) in gauss_pts:
1580
+ # Shape function derivatives w.r.t. natural coords
1581
+ dN_dxi = np.array([-(1-eta), (1-eta), (1+eta), -(1+eta)]) * 0.25
1582
+ dN_deta = np.array([-(1-xi), -(1+xi), (1+xi), (1-xi)]) * 0.25
1583
+ # Jacobian
1584
+ J = np.zeros((2,2))
1585
+ for a in range(4):
1586
+ J[0,0] += dN_dxi[a] * nodes_elem[a,0]
1587
+ J[0,1] += dN_dxi[a] * nodes_elem[a,1]
1588
+ J[1,0] += dN_deta[a] * nodes_elem[a,0]
1589
+ J[1,1] += dN_deta[a] * nodes_elem[a,1]
1590
+ detJ = np.linalg.det(J)
1591
+ if detJ <= 0:
1592
+ continue
1593
+ Jinv = np.linalg.inv(J)
1594
+ # Shape function derivatives w.r.t. x,y
1595
+ dN_dx = Jinv[0,0]*dN_dxi + Jinv[0,1]*dN_deta
1596
+ dN_dy = Jinv[1,0]*dN_dxi + Jinv[1,1]*dN_deta
1597
+ gradN = np.vstack((dN_dx, dN_dy)) # shape (2,4)
1598
+ # Compute grad(h) at this Gauss point
1599
+ grad_h = gradN @ h_elem
1600
+ # Hydraulic gradient i = -grad(h)
1601
+ i_gp = -grad_h
1602
+ # Distribute/average to nodes
1603
+ for node in element_nodes[:4]:
1604
+ gradient[node] += i_gp
1605
+ count[node] += 1
1606
+ elif element_type == 6:
1607
+ # 6-node triangle (quadratic): compute gradient using 3-point Gauss quadrature
1608
+ nodes_elem = nodes[element_nodes[:6], :]
1609
+ h_elem = head[element_nodes[:6]]
1610
+
1611
+ # 3-point Gauss quadrature for triangles
1612
+ gauss_pts = [(1/6, 1/6, 2/3), (1/6, 2/3, 1/6), (2/3, 1/6, 1/6)]
1613
+ weights = [1/3, 1/3, 1/3]
1614
+
1615
+ for (L1, L2, L3), w in zip(gauss_pts, weights):
1616
+ # Shape function derivatives w.r.t. area coordinates
1617
+ dN_dL1 = np.array([4*L1-1, 0, 0, 4*L2, 0, 4*L3])
1618
+ dN_dL2 = np.array([0, 4*L2-1, 0, 4*L1, 4*L3, 0])
1619
+ dN_dL3 = np.array([0, 0, 4*L3-1, 0, 4*L2, 4*L1])
1620
+
1621
+ # Jacobian transformation
1622
+ x0, y0 = nodes_elem[0]
1623
+ x1, y1 = nodes_elem[1]
1624
+ x2, y2 = nodes_elem[2]
1625
+
1626
+ J = np.array([[x0 - x2, x1 - x2],
1627
+ [y0 - y2, y1 - y2]])
1628
+
1629
+ detJ = np.linalg.det(J)
1630
+ if abs(detJ) < 1e-10:
1631
+ continue
1632
+
1633
+ Jinv = np.linalg.inv(J)
1634
+
1635
+ # Transform derivatives to global coordinates
1636
+ dN_dx = Jinv[0,0] * (dN_dL1 - dN_dL3) + Jinv[0,1] * (dN_dL2 - dN_dL3)
1637
+ dN_dy = Jinv[1,0] * (dN_dL1 - dN_dL3) + Jinv[1,1] * (dN_dL2 - dN_dL3)
1638
+ gradN = np.vstack((dN_dx, dN_dy)) # shape (2,6)
1639
+
1640
+ # Compute grad(h) at this Gauss point
1641
+ grad_h = gradN @ h_elem
1642
+ # Hydraulic gradient i = -grad(h)
1643
+ i_gp = -grad_h
1644
+
1645
+ # Distribute gradient to all 6 nodes of tri6 element
1646
+ for node in element_nodes[:6]:
1647
+ gradient[node] += i_gp * w # Weight by Gauss weight
1648
+ count[node] += w
1649
+
1650
+ count[count == 0] = 1 # Avoid division by zero
1651
+ gradient /= count[:, None]
1652
+ return gradient
1653
+
1518
1654
  def tri3_stiffness_matrix(nodes_elem, Kmat):
1519
1655
  """
1520
1656
  Compute the 3x3 local stiffness matrix for a 3-node triangular element.
@@ -1855,7 +1991,16 @@ def run_seepage_analysis(seep_data):
1855
1991
  seep_data: Dictionary containing all the seepage data
1856
1992
 
1857
1993
  Returns:
1858
- Dictionary containing solution results
1994
+ Dictionary containing solution results with the following keys:
1995
+ - 'head': numpy array of hydraulic head values at each node
1996
+ - 'u': numpy array of pore pressure values at each node
1997
+ - 'velocity': numpy array of shape (n_nodes, 2) containing velocity vectors [vx, vy] at each node
1998
+ - 'gradient': numpy array of shape (n_nodes, 2) containing hydraulic gradient vectors [ix, iy] at each node
1999
+ - 'v_mag': numpy array of velocity magnitude at each node
2000
+ - 'i_mag': numpy array of hydraulic gradient magnitude at each node
2001
+ - 'q': numpy array of nodal flow vector
2002
+ - 'phi': numpy array of stream function/flow potential values at each node
2003
+ - 'flowrate': scalar total flow rate
1859
2004
  """
1860
2005
  # Extract data from seep_data
1861
2006
  nodes = seep_data["nodes"]
@@ -1920,6 +2065,13 @@ def run_seepage_analysis(seep_data):
1920
2065
  # Compute velocity, don't pass kr0 and h0
1921
2066
  velocity = compute_velocity(nodes, elements, head, k1, k2, angle, element_types=element_types)
1922
2067
 
2068
+ # Compute hydraulic gradient i = -grad(h)
2069
+ gradient = compute_gradient(nodes, elements, head, element_types)
2070
+
2071
+ # Compute velocity and gradient magnitudes
2072
+ v_mag = np.linalg.norm(velocity, axis=1)
2073
+ i_mag = np.linalg.norm(gradient, axis=1)
2074
+
1923
2075
  gamma_w = unit_weight
1924
2076
  u = gamma_w * (head - nodes[:, 1])
1925
2077
 
@@ -1927,6 +2079,9 @@ def run_seepage_analysis(seep_data):
1927
2079
  "head": head,
1928
2080
  "u": u,
1929
2081
  "velocity": velocity,
2082
+ "gradient": gradient,
2083
+ "v_mag": v_mag,
2084
+ "i_mag": i_mag,
1930
2085
  "q": q,
1931
2086
  "phi": phi,
1932
2087
  "flowrate": total_flow
@@ -1937,10 +2092,21 @@ def run_seepage_analysis(seep_data):
1937
2092
  def export_seep_solution(seep_data, solution, filename):
1938
2093
  """Exports nodal results to a CSV file.
1939
2094
 
2095
+ The exported CSV file contains the following columns:
2096
+ - node_id: Node identifier (1-based)
2097
+ - head: Hydraulic head at each node
2098
+ - u: Pore pressure at each node
2099
+ - v_x, v_y: Velocity vector components
2100
+ - v_mag: Velocity magnitude
2101
+ - i_x, i_y: Hydraulic gradient vector components
2102
+ - i_mag: Hydraulic gradient magnitude
2103
+ - q: Nodal flow vector
2104
+ - phi: Stream function/flow potential
2105
+
1940
2106
  Args:
1941
2107
  filename: Path to the output CSV file
1942
2108
  seep_data: Dictionary containing seepage data
1943
- solution: Dictionary containing solution results from run_analysis
2109
+ solution: Dictionary containing solution results from run_seepage_analysis
1944
2110
  """
1945
2111
  import pandas as pd
1946
2112
  n_nodes = len(seep_data["nodes"])
@@ -1950,7 +2116,10 @@ def export_seep_solution(seep_data, solution, filename):
1950
2116
  "u": solution["u"],
1951
2117
  "v_x": solution["velocity"][:, 0],
1952
2118
  "v_y": solution["velocity"][:, 1],
1953
- "v_mag": np.linalg.norm(solution["velocity"], axis=1),
2119
+ "v_mag": solution["v_mag"],
2120
+ "i_x": solution["gradient"][:, 0],
2121
+ "i_y": solution["gradient"][:, 1],
2122
+ "i_mag": solution["i_mag"],
1954
2123
  "q": solution["q"],
1955
2124
  "phi": solution["phi"]
1956
2125
  })
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xslope
3
- Version: 0.1.7
3
+ Version: 0.1.9
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
@@ -1,5 +1,5 @@
1
1
  xslope/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
- xslope/_version.py,sha256=Lc9xqzzg7cCgDTKs34dvk6NG0CArmowG_5qV27pZmSs,50
2
+ xslope/_version.py,sha256=zvdgcTZN9Sqg_0LnmeAQEgKa85RkCrIkfxKFqzUQC6o,50
3
3
  xslope/advanced.py,sha256=35k_ekQJ-mQJ1wHnoIHMc5TVfYn-2EPCJyHz827Cpbc,18281
4
4
  xslope/fem.py,sha256=K4_Pq06HFBpRkN3JwtXF2zw_AMnCkXvj0ggrlRFMQQw,115731
5
5
  xslope/fileio.py,sha256=DnFUYmJedjKXOuVPZUfTRxGfTjiIz8KyHkRDK7ddQg0,28840
@@ -8,14 +8,14 @@ xslope/mesh copy.py,sha256=qtMH1yKFgHM4kNuIrxco7tKV86R3Dbf7Nok5j6MtlLY,131013
8
8
  xslope/mesh.py,sha256=qtMH1yKFgHM4kNuIrxco7tKV86R3Dbf7Nok5j6MtlLY,131013
9
9
  xslope/plot.py,sha256=OW2eZyrT5h3Y95qjNFgGMnC_Am7TurUB2S7b_BgnO6E,54641
10
10
  xslope/plot_fem.py,sha256=al9zjqjxWKooLl4SAds77Zz-j9cjD4TJGygyU9QK5vo,71111
11
- xslope/plot_seep.py,sha256=3wbKp85cmK_6EniFnK9x-FaZtYBZ3KZbRn9U1GsInmk,28775
11
+ xslope/plot_seep.py,sha256=Fs8S-0_7bnNJZlj7SnM0ij1mFDZWlNjXGnP6iMDiplY,34647
12
12
  xslope/search.py,sha256=dvgKn8JCobuvyD7fClF5lcbeHESCvV8gZ_U_lQnYRok,16867
13
- xslope/seep.py,sha256=zVX8NJOp8e6VJ6y99YLkmOh_RPQFly9Z9UI3tka6yQQ,85765
13
+ xslope/seep.py,sha256=tLvme-eL0R5SGGTH2Y6z4Rrfe36UuSWWLlL_1kglee8,93030
14
14
  xslope/slice.py,sha256=QHawTk7XPLziHoN_ZS0jrEPYKlhPT62caUc_q-_EGjs,45236
15
15
  xslope/solve.py,sha256=j7N66QBjBpDAo-aizTiP8auwd5Ey1SiYAYeySaMVzkw,48554
16
- xslope-0.1.7.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
17
- xslope-0.1.7.dist-info/METADATA,sha256=9oE9ygroQ0pg5sj1iz3KZ4GxKCUYg0N2oNDh9Kks6jI,2027
18
- xslope-0.1.7.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
19
- xslope-0.1.7.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
20
- xslope-0.1.7.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
21
- xslope-0.1.7.dist-info/RECORD,,
16
+ xslope-0.1.9.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
17
+ xslope-0.1.9.dist-info/METADATA,sha256=Q-IPfFHUfGovtxSEjzQI2AeOlAyjd-ne0343IVmClFM,2027
18
+ xslope-0.1.9.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
19
+ xslope-0.1.9.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
20
+ xslope-0.1.9.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
21
+ xslope-0.1.9.dist-info/RECORD,,
File without changes