xslope 0.1.6__py3-none-any.whl → 0.1.8__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/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.6
3
+ Version: 0.1.8
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=NdJ0AO0Uqe8qXyVhnXjyePxheMvSfPnlWIjEyON0wio,50
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=lPMaKbm4VURWDb1lwtLT7UhuEwuXi5cKRQw3mKt4HkM,34657
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=j7N66QBjBpDAo-aizTiP8auwd5Ey1SiYAYeySaMVzkw,48554
16
+ xslope-0.1.8.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
17
+ xslope-0.1.8.dist-info/METADATA,sha256=Pf0XtMc9nlYRojBMzwsvKv4izxJh32ydwOQwCUmUhzA,2027
18
+ xslope-0.1.8.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
19
+ xslope-0.1.8.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
20
+ xslope-0.1.8.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
21
+ xslope-0.1.8.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- xslope/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
- xslope/_version.py,sha256=El5otyOm5tn7_NTNUcawnWQ_lZMwfYOTw_-GGhANHSI,50
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.py,sha256=OhaAMlunbO86Sx4iF5sRsk4eEN7-AG-_TYPUvYVTGA4,122513
8
- xslope/plot.py,sha256=rr1D-6KzYyJtq51o4yLyaFkowBa1LtygIk9rtA3GxgQ,54592
9
- xslope/plot_fem.py,sha256=al9zjqjxWKooLl4SAds77Zz-j9cjD4TJGygyU9QK5vo,71111
10
- xslope/plot_seep.py,sha256=3wbKp85cmK_6EniFnK9x-FaZtYBZ3KZbRn9U1GsInmk,28775
11
- xslope/search.py,sha256=dvgKn8JCobuvyD7fClF5lcbeHESCvV8gZ_U_lQnYRok,16867
12
- xslope/seep.py,sha256=zVX8NJOp8e6VJ6y99YLkmOh_RPQFly9Z9UI3tka6yQQ,85765
13
- xslope/slice.py,sha256=QHawTk7XPLziHoN_ZS0jrEPYKlhPT62caUc_q-_EGjs,45236
14
- xslope/solve.py,sha256=j7N66QBjBpDAo-aizTiP8auwd5Ey1SiYAYeySaMVzkw,48554
15
- xslope-0.1.6.dist-info/LICENSE,sha256=NU5J88FUai_4Ixu5DqOQukA-gcXAyX8pXLhIg8OB3AM,10969
16
- xslope-0.1.6.dist-info/METADATA,sha256=8eM1VvzchbN-xSlSrTzbRMX86Vy2L3WDUVrdt3_BJq4,2027
17
- xslope-0.1.6.dist-info/NOTICE,sha256=E-sbN0MWwvJC27Z-2_G4VUHIx4IsfvLDTmOstvY4-OQ,530
18
- xslope-0.1.6.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
19
- xslope-0.1.6.dist-info/top_level.txt,sha256=5qHbWJ1R2pdTNIainFyrVtFk8R1tRcwIn0kzTuwuV1Q,7
20
- xslope-0.1.6.dist-info/RECORD,,
File without changes