Python-snippets/TM1/trussSolver2d.py

127 lines
3.9 KiB
Python
Raw Normal View History

2024-11-25 14:39:41 +01:00
import numpy as np
class truss:
n: int
s: int
nodes: np.ndarray
externalForces: list[list]
beams: np.ndarray
beamForces: np.ndarray
# n: number nodes
# s: number beams
# externalForces: list of externalForces each force is list with [Fx, Fy, NodeIndex] so a single force in y direction on node 3 would look like: [[0,F,3]] (zero indexed!!)
# nodeCoordinates: noarray of nodes x and y coordinates: [[x1,y1],[x2,y2]]
# beams: ndarray of beams every beam contains node indices it connects. e.g. beam0 connnects nodes 0 and 1 -> beams= [[0,1]]
def __init__(
self,
s: int,
n: int,
externalForces: list,
nodeCoordinates: np.ndarray,
beams: np.ndarray,
):
self.n = n
self.s = s
self.externalForces = externalForces
self.nodes = nodeCoordinates
self.beams = beams
def solve(self):
# coeficient matrices A in x and y dir. with #beams rows and #nodes cols
# Ax,Ay is padded because numpy requires square coefficient matrix
# Ax and Ay are concatenated efter lineaer system is constructed
Ax = np.zeros((self.n, 2 * self.n)) # lhsx
Ay = np.zeros((self.n, 2 * self.n)) # lhsy
# rhs vectors all zero or external force
bx = np.zeros(self.n)
by = np.zeros((self.n))
for ef in self.externalForces:
bx[ef[2]] = ef[0]
by[ef[2]] = ef[1]
# construct lgs
for ni in range(len(self.nodes)): # for every node index ni
for b in np.where(self.beams == ni)[
0
]: # for every beam connected to node[ni]
(x1, y1) = self.nodes[self.beams[b][0]]
(x2, y2) = self.nodes[self.beams[b][1]]
# find deltaX and deltaY of beam to calculate force components
vy, vx = 0, 0
2024-11-25 15:32:39 +01:00
# if (
# b < (2 * ni) and ni > 0
# ): # find force direction for beams on left side of node
if self.beams[b][0] != ni:
2024-11-25 14:39:41 +01:00
vy = y1 - y2
vx = x1 - x2
else: # different force direction for nodes on right side of node
vy = y2 - y1
vx = x2 - x1
lv = np.sqrt(vx**2 + vy**2) # |v|
ux = ((1 / lv) if lv != 0 else 0) * vx # (v^)x unit vector X
uy = ((1 / lv) if lv != 0 else 0) * vy # (v^)y unit vector Y
Ax[ni, b] = ux # koeffizient stabkraft F[b] an node[ni] in x richtung
Ay[ni, b] = uy # koeffizient stabkraft F[b] an node[ni] in y richtung
A = np.concatenate((Ax, Ay), axis=0)
b = np.concatenate((bx, by), axis=0)
self.beamForces = np.linalg.lstsq(A, b)[0]
def print(self):
[
print(f"F{i+1}: {n:#.3g} kN")
for i, n in enumerate(self.beamForces)
if n != 0
] # ignore padding collumns
### sample useage
## TM1 Aufgabe 164
if __name__ == "__main__":
n = 15 # nr. nodes
s = 2 * n - 3 # 27 beams(0-26) + F[27]+ Fa[28] + Fb[29]
F = 28
Fa = (((n - 3) / 2) * F) / 2
Fb = Fa
## Node x and y coordinates
nodes = np.array([[i, 0 if i % 2 == 0 else 2] for i in range(n)])
# ExternalForces (x,y,nodeIndex)
externalForces = [
[0, Fa, 0],
[0, -F, 2],
[0, -F, 4],
[0, -F, 6],
[0, -F, 8],
[0, -F, 10],
[0, -F, 12],
[0, Fb, 14],
]
## beams each row represents a beam and contains the node indices it connects to
beams = np.array(
[
[
x / 2 if x % 2 == 0 else (x - 1) / 2,
x / 2 + 1 if x % 2 == 0 else (x - 1) / 2 + 2,
]
for x in range(s)
],
dtype=int,
)
t = truss(s, n, externalForces, nodes, beams)
t.solve()
t.print()