switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
__all__ = ['Beam',
|
||||
'Truss',
|
||||
'Cable',
|
||||
'Arch'
|
||||
]
|
||||
|
||||
from .beam import Beam
|
||||
from .truss import Truss
|
||||
from .cable import Cable
|
||||
from .arch import Arch
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,815 @@
|
||||
"""
|
||||
This module can be used to solve problems related
|
||||
to 2D Cables.
|
||||
"""
|
||||
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.core.symbol import Symbol,symbols
|
||||
from sympy import sin, cos, pi, atan, diff, Piecewise, solve, rad
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.solvers.solveset import linsolve
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.plotting import plot
|
||||
|
||||
class Cable:
|
||||
"""
|
||||
Cables are structures in engineering that support
|
||||
the applied transverse loads through the tensile
|
||||
resistance developed in its members.
|
||||
|
||||
Cables are widely used in suspension bridges, tension
|
||||
leg offshore platforms, transmission lines, and find
|
||||
use in several other engineering applications.
|
||||
|
||||
Examples
|
||||
========
|
||||
A cable is supported at (0, 10) and (10, 10). Two point loads
|
||||
acting vertically downwards act on the cable, one with magnitude 3 kN
|
||||
and acting 2 meters from the left support and 3 meters below it, while
|
||||
the other with magnitude 2 kN is 6 meters from the left support and
|
||||
6 meters below it.
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.apply_load(-1, ('P', 2, 7, 3, 270))
|
||||
>>> c.apply_load(-1, ('Q', 6, 4, 2, 270))
|
||||
>>> c.loads
|
||||
{'distributed': {}, 'point_load': {'P': [3, 270], 'Q': [2, 270]}}
|
||||
>>> c.loads_position
|
||||
{'P': [2, 7], 'Q': [6, 4]}
|
||||
"""
|
||||
def __init__(self, support_1, support_2):
|
||||
"""
|
||||
Initializes the class.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
support_1 and support_2 are tuples of the form
|
||||
(label, x, y), where
|
||||
|
||||
label : String or symbol
|
||||
The label of the support
|
||||
|
||||
x : Sympifyable
|
||||
The x coordinate of the position of the support
|
||||
|
||||
y : Sympifyable
|
||||
The y coordinate of the position of the support
|
||||
"""
|
||||
self._left_support = []
|
||||
self._right_support = []
|
||||
self._supports = {}
|
||||
self._support_labels = []
|
||||
self._loads = {"distributed": {}, "point_load": {}}
|
||||
self._loads_position = {}
|
||||
self._length = 0
|
||||
self._reaction_loads = {}
|
||||
self._tension = {}
|
||||
self._lowest_x_global = sympify(0)
|
||||
self._lowest_y_global = sympify(0)
|
||||
self._cable_eqn = None
|
||||
self._tension_func = None
|
||||
if support_1[0] == support_2[0]:
|
||||
raise ValueError("Supports can not have the same label")
|
||||
|
||||
elif support_1[1] == support_2[1]:
|
||||
raise ValueError("Supports can not be at the same location")
|
||||
|
||||
x1 = sympify(support_1[1])
|
||||
y1 = sympify(support_1[2])
|
||||
self._supports[support_1[0]] = [x1, y1]
|
||||
|
||||
x2 = sympify(support_2[1])
|
||||
y2 = sympify(support_2[2])
|
||||
self._supports[support_2[0]] = [x2, y2]
|
||||
|
||||
if support_1[1] < support_2[1]:
|
||||
self._left_support.append(x1)
|
||||
self._left_support.append(y1)
|
||||
self._right_support.append(x2)
|
||||
self._right_support.append(y2)
|
||||
self._support_labels.append(support_1[0])
|
||||
self._support_labels.append(support_2[0])
|
||||
|
||||
else:
|
||||
self._left_support.append(x2)
|
||||
self._left_support.append(y2)
|
||||
self._right_support.append(x1)
|
||||
self._right_support.append(y1)
|
||||
self._support_labels.append(support_2[0])
|
||||
self._support_labels.append(support_1[0])
|
||||
|
||||
for i in self._support_labels:
|
||||
self._reaction_loads[Symbol("R_"+ i +"_x")] = 0
|
||||
self._reaction_loads[Symbol("R_"+ i +"_y")] = 0
|
||||
|
||||
@property
|
||||
def supports(self):
|
||||
"""
|
||||
Returns the supports of the cable along with their
|
||||
positions.
|
||||
"""
|
||||
return self._supports
|
||||
|
||||
@property
|
||||
def left_support(self):
|
||||
"""
|
||||
Returns the position of the left support.
|
||||
"""
|
||||
return self._left_support
|
||||
|
||||
@property
|
||||
def right_support(self):
|
||||
"""
|
||||
Returns the position of the right support.
|
||||
"""
|
||||
return self._right_support
|
||||
|
||||
@property
|
||||
def loads(self):
|
||||
"""
|
||||
Returns the magnitude and direction of the loads
|
||||
acting on the cable.
|
||||
"""
|
||||
return self._loads
|
||||
|
||||
@property
|
||||
def loads_position(self):
|
||||
"""
|
||||
Returns the position of the point loads acting on the
|
||||
cable.
|
||||
"""
|
||||
return self._loads_position
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
"""
|
||||
Returns the length of the cable.
|
||||
"""
|
||||
return self._length
|
||||
|
||||
@property
|
||||
def reaction_loads(self):
|
||||
"""
|
||||
Returns the reaction forces at the supports, which are
|
||||
initialized to 0.
|
||||
"""
|
||||
return self._reaction_loads
|
||||
|
||||
@property
|
||||
def tension(self):
|
||||
"""
|
||||
Returns the tension developed in the cable due to the loads
|
||||
applied.
|
||||
"""
|
||||
return self._tension
|
||||
|
||||
def tension_at(self, x):
|
||||
"""
|
||||
Returns the tension at a given value of x developed due to
|
||||
distributed load.
|
||||
"""
|
||||
if 'distributed' not in self._tension.keys():
|
||||
raise ValueError("No distributed load added or solve method not called")
|
||||
|
||||
if x > self._right_support[0] or x < self._left_support[0]:
|
||||
raise ValueError("The value of x should be between the two supports")
|
||||
|
||||
A = self._tension['distributed']
|
||||
X = Symbol('X')
|
||||
|
||||
return A.subs({X:(x-self._lowest_x_global)})
|
||||
|
||||
def apply_length(self, length):
|
||||
"""
|
||||
This method specifies the length of the cable
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
length : Sympifyable
|
||||
The length of the cable
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.apply_length(20)
|
||||
>>> c.length
|
||||
20
|
||||
"""
|
||||
dist = ((self._left_support[0] - self._right_support[0])**2
|
||||
- (self._left_support[1] - self._right_support[1])**2)**(1/2)
|
||||
|
||||
if length < dist:
|
||||
raise ValueError("length should not be less than the distance between the supports")
|
||||
|
||||
self._length = length
|
||||
|
||||
def change_support(self, label, new_support):
|
||||
"""
|
||||
This method changes the mentioned support with a new support.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
label: String or symbol
|
||||
The label of the support to be changed
|
||||
|
||||
new_support: Tuple of the form (new_label, x, y)
|
||||
new_label: String or symbol
|
||||
The label of the new support
|
||||
|
||||
x: Sympifyable
|
||||
The x-coordinate of the position of the new support.
|
||||
|
||||
y: Sympifyable
|
||||
The y-coordinate of the position of the new support.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.supports
|
||||
{'A': [0, 10], 'B': [10, 10]}
|
||||
>>> c.change_support('B', ('C', 5, 6))
|
||||
>>> c.supports
|
||||
{'A': [0, 10], 'C': [5, 6]}
|
||||
"""
|
||||
if label not in self._supports:
|
||||
raise ValueError("No support exists with the given label")
|
||||
|
||||
i = self._support_labels.index(label)
|
||||
rem_label = self._support_labels[(i+1)%2]
|
||||
x1 = self._supports[rem_label][0]
|
||||
y1 = self._supports[rem_label][1]
|
||||
|
||||
x = sympify(new_support[1])
|
||||
y = sympify(new_support[2])
|
||||
|
||||
for l in self._loads_position:
|
||||
if l[0] >= max(x, x1) or l[0] <= min(x, x1):
|
||||
raise ValueError("The change in support will throw an existing load out of range")
|
||||
|
||||
self._supports.pop(label)
|
||||
self._left_support.clear()
|
||||
self._right_support.clear()
|
||||
self._reaction_loads.clear()
|
||||
self._support_labels.remove(label)
|
||||
|
||||
self._supports[new_support[0]] = [x, y]
|
||||
|
||||
if x1 < x:
|
||||
self._left_support.append(x1)
|
||||
self._left_support.append(y1)
|
||||
self._right_support.append(x)
|
||||
self._right_support.append(y)
|
||||
self._support_labels.append(new_support[0])
|
||||
|
||||
else:
|
||||
self._left_support.append(x)
|
||||
self._left_support.append(y)
|
||||
self._right_support.append(x1)
|
||||
self._right_support.append(y1)
|
||||
self._support_labels.insert(0, new_support[0])
|
||||
|
||||
for i in self._support_labels:
|
||||
self._reaction_loads[Symbol("R_"+ i +"_x")] = 0
|
||||
self._reaction_loads[Symbol("R_"+ i +"_y")] = 0
|
||||
|
||||
def apply_load(self, order, load):
|
||||
"""
|
||||
This method adds load to the cable.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
order : Integer
|
||||
The order of the applied load.
|
||||
|
||||
- For point loads, order = -1
|
||||
- For distributed load, order = 0
|
||||
|
||||
load : tuple
|
||||
|
||||
* For point loads, load is of the form (label, x, y, magnitude, direction), where:
|
||||
|
||||
label : String or symbol
|
||||
The label of the load
|
||||
|
||||
x : Sympifyable
|
||||
The x coordinate of the position of the load
|
||||
|
||||
y : Sympifyable
|
||||
The y coordinate of the position of the load
|
||||
|
||||
magnitude : Sympifyable
|
||||
The magnitude of the load. It must always be positive
|
||||
|
||||
direction : Sympifyable
|
||||
The angle, in degrees, that the load vector makes with the horizontal
|
||||
in the counter-clockwise direction. It takes the values 0 to 360,
|
||||
inclusive.
|
||||
|
||||
|
||||
* For uniformly distributed load, load is of the form (label, magnitude)
|
||||
|
||||
label : String or symbol
|
||||
The label of the load
|
||||
|
||||
magnitude : Sympifyable
|
||||
The magnitude of the load. It must always be positive
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For a point load of magnitude 12 units inclined at 30 degrees with the horizontal:
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.apply_load(-1, ('Z', 5, 5, 12, 30))
|
||||
>>> c.loads
|
||||
{'distributed': {}, 'point_load': {'Z': [12, 30]}}
|
||||
>>> c.loads_position
|
||||
{'Z': [5, 5]}
|
||||
|
||||
|
||||
For a uniformly distributed load of magnitude 9 units:
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.apply_load(0, ('X', 9))
|
||||
>>> c.loads
|
||||
{'distributed': {'X': 9}, 'point_load': {}}
|
||||
"""
|
||||
if order == -1:
|
||||
if len(self._loads["distributed"]) != 0:
|
||||
raise ValueError("Distributed load already exists")
|
||||
|
||||
label = load[0]
|
||||
if label in self._loads["point_load"]:
|
||||
raise ValueError("Label already exists")
|
||||
|
||||
x = sympify(load[1])
|
||||
y = sympify(load[2])
|
||||
|
||||
if x > self._right_support[0] or x < self._left_support[0]:
|
||||
raise ValueError("The load should be positioned between the supports")
|
||||
|
||||
magnitude = sympify(load[3])
|
||||
direction = sympify(load[4])
|
||||
|
||||
self._loads["point_load"][label] = [magnitude, direction]
|
||||
self._loads_position[label] = [x, y]
|
||||
|
||||
elif order == 0:
|
||||
if len(self._loads_position) != 0:
|
||||
raise ValueError("Point load(s) already exist")
|
||||
|
||||
label = load[0]
|
||||
if label in self._loads["distributed"]:
|
||||
raise ValueError("Label already exists")
|
||||
|
||||
magnitude = sympify(load[1])
|
||||
|
||||
self._loads["distributed"][label] = magnitude
|
||||
|
||||
else:
|
||||
raise ValueError("Order should be either -1 or 0")
|
||||
|
||||
def remove_loads(self, *args):
|
||||
"""
|
||||
This methods removes the specified loads.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
This input takes multiple label(s) as input
|
||||
label(s): String or symbol
|
||||
The label(s) of the loads to be removed.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
>>> c.apply_load(-1, ('Z', 5, 5, 12, 30))
|
||||
>>> c.loads
|
||||
{'distributed': {}, 'point_load': {'Z': [12, 30]}}
|
||||
>>> c.remove_loads('Z')
|
||||
>>> c.loads
|
||||
{'distributed': {}, 'point_load': {}}
|
||||
"""
|
||||
for i in args:
|
||||
if len(self._loads_position) == 0:
|
||||
if i not in self._loads['distributed']:
|
||||
raise ValueError("Error removing load " + i + ": no such load exists")
|
||||
|
||||
else:
|
||||
self._loads['disrtibuted'].pop(i)
|
||||
|
||||
else:
|
||||
if i not in self._loads['point_load']:
|
||||
raise ValueError("Error removing load " + i + ": no such load exists")
|
||||
|
||||
else:
|
||||
self._loads['point_load'].pop(i)
|
||||
self._loads_position.pop(i)
|
||||
|
||||
def solve(self, *args):
|
||||
"""
|
||||
This method solves for the reaction forces at the supports, the tension developed in
|
||||
the cable, and updates the length of the cable.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
This method requires no input when solving for point loads
|
||||
For distributed load, the x and y coordinates of the lowest point of the cable are
|
||||
required as
|
||||
|
||||
x: Sympifyable
|
||||
The x coordinate of the lowest point
|
||||
|
||||
y: Sympifyable
|
||||
The y coordinate of the lowest point
|
||||
|
||||
Examples
|
||||
========
|
||||
For point loads,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(("A", 0, 10), ("B", 10, 10))
|
||||
>>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270))
|
||||
>>> c.apply_load(-1, ('X', 4, 6, 8, 270))
|
||||
>>> c.solve()
|
||||
>>> c.tension
|
||||
{A_Z: 8.91403453669861, X_B: 19*sqrt(13)/10, Z_X: 4.79150773600774}
|
||||
>>> c.reaction_loads
|
||||
{R_A_x: -5.25547445255474, R_A_y: 7.2, R_B_x: 5.25547445255474, R_B_y: 3.8}
|
||||
>>> c.length
|
||||
5.7560958484519 + 2*sqrt(13)
|
||||
|
||||
For distributed load,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c=Cable(("A", 0, 40),("B", 100, 20))
|
||||
>>> c.apply_load(0, ("X", 850))
|
||||
>>> c.solve(58.58)
|
||||
>>> c.tension
|
||||
{'distributed': 36465.0*sqrt(0.00054335718671383*X**2 + 1)}
|
||||
>>> c.tension_at(0)
|
||||
61717.4130533677
|
||||
>>> c.reaction_loads
|
||||
{R_A_x: 36465.0, R_A_y: -49793.0, R_B_x: 44399.9537590861, R_B_y: 42868.2071025955}
|
||||
"""
|
||||
|
||||
if len(self._loads_position) != 0:
|
||||
sorted_position = sorted(self._loads_position.items(), key = lambda item : item[1][0])
|
||||
|
||||
sorted_position.append(self._support_labels[1])
|
||||
sorted_position.insert(0, self._support_labels[0])
|
||||
|
||||
self._tension.clear()
|
||||
moment_sum_from_left_support = 0
|
||||
moment_sum_from_right_support = 0
|
||||
F_x = 0
|
||||
F_y = 0
|
||||
self._length = 0
|
||||
tension_func = []
|
||||
x = symbols('x')
|
||||
for i in range(1, len(sorted_position)-1):
|
||||
if i == 1:
|
||||
self._length+=sqrt((self._left_support[0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._left_support[1] - self._loads_position[sorted_position[i][0]][1])**2)
|
||||
|
||||
else:
|
||||
self._length+=sqrt((self._loads_position[sorted_position[i-1][0]][0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._loads_position[sorted_position[i-1][0]][1] - self._loads_position[sorted_position[i][0]][1])**2)
|
||||
|
||||
if i == len(sorted_position)-2:
|
||||
self._length+=sqrt((self._right_support[0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._right_support[1] - self._loads_position[sorted_position[i][0]][1])**2)
|
||||
|
||||
moment_sum_from_left_support += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._left_support[1] - self._loads_position[sorted_position[i][0]][1])
|
||||
moment_sum_from_left_support += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._left_support[0] - self._loads_position[sorted_position[i][0]][0])
|
||||
|
||||
F_x += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180)
|
||||
F_y += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180)
|
||||
|
||||
label = Symbol(sorted_position[i][0]+"_"+sorted_position[i+1][0])
|
||||
y2 = self._loads_position[sorted_position[i][0]][1]
|
||||
x2 = self._loads_position[sorted_position[i][0]][0]
|
||||
y1 = 0
|
||||
x1 = 0
|
||||
|
||||
if i == len(sorted_position)-2:
|
||||
x1 = self._right_support[0]
|
||||
y1 = self._right_support[1]
|
||||
|
||||
else:
|
||||
x1 = self._loads_position[sorted_position[i+1][0]][0]
|
||||
y1 = self._loads_position[sorted_position[i+1][0]][1]
|
||||
|
||||
angle_with_horizontal = atan((y1 - y2)/(x1 - x2))
|
||||
|
||||
tension = -(moment_sum_from_left_support)/(abs(self._left_support[1] - self._loads_position[sorted_position[i][0]][1])*cos(angle_with_horizontal) + abs(self._left_support[0] - self._loads_position[sorted_position[i][0]][0])*sin(angle_with_horizontal))
|
||||
self._tension[label] = tension
|
||||
tension_func.append((tension, x<=x1))
|
||||
moment_sum_from_right_support += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._right_support[1] - self._loads_position[sorted_position[i][0]][1])
|
||||
moment_sum_from_right_support += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._right_support[0] - self._loads_position[sorted_position[i][0]][0])
|
||||
|
||||
label = Symbol(sorted_position[0][0]+"_"+sorted_position[1][0])
|
||||
y2 = self._loads_position[sorted_position[1][0]][1]
|
||||
x2 = self._loads_position[sorted_position[1][0]][0]
|
||||
x1 = self._left_support[0]
|
||||
y1 = self._left_support[1]
|
||||
|
||||
angle_with_horizontal = -atan((y2 - y1)/(x2 - x1))
|
||||
tension = -(moment_sum_from_right_support)/(abs(self._right_support[1] - self._loads_position[sorted_position[1][0]][1])*cos(angle_with_horizontal) + abs(self._right_support[0] - self._loads_position[sorted_position[1][0]][0])*sin(angle_with_horizontal))
|
||||
self._tension[label] = tension
|
||||
|
||||
tension_func.insert(0,(tension, x<=x2))
|
||||
self._tension_func = Piecewise(*tension_func)
|
||||
angle_with_horizontal = pi/2 - angle_with_horizontal
|
||||
label = self._support_labels[0]
|
||||
self._reaction_loads[Symbol("R_"+label+"_x")] = -sin(angle_with_horizontal) * tension
|
||||
F_x += -sin(angle_with_horizontal) * tension
|
||||
self._reaction_loads[Symbol("R_"+label+"_y")] = cos(angle_with_horizontal) * tension
|
||||
F_y += cos(angle_with_horizontal) * tension
|
||||
|
||||
label = self._support_labels[1]
|
||||
self._reaction_loads[Symbol("R_"+label+"_x")] = -F_x
|
||||
self._reaction_loads[Symbol("R_"+label+"_y")] = -F_y
|
||||
|
||||
elif len(self._loads['distributed']) != 0 :
|
||||
|
||||
if len(args) == 0:
|
||||
raise ValueError("Provide the lowest point of the cable")
|
||||
|
||||
lowest_x = sympify(args[0])
|
||||
self._lowest_x_global = lowest_x
|
||||
|
||||
a = Symbol('a', positive=True)
|
||||
c = Symbol('c')
|
||||
# augmented matrix form of linsolve
|
||||
|
||||
M = Matrix(
|
||||
[[(self._left_support[0]-lowest_x)**2, 1, self._left_support[1]],
|
||||
[(self._right_support[0]-lowest_x)**2, 1, self._right_support[1]],
|
||||
])
|
||||
|
||||
coefficient_solution = list(linsolve(M, (a, c)))
|
||||
if len(coefficient_solution) ==0 or coefficient_solution[0][0]== 0:
|
||||
raise ValueError("The lowest point is inconsistent with the supports")
|
||||
|
||||
A = coefficient_solution[0][0]
|
||||
C = coefficient_solution[0][1] + coefficient_solution[0][0]*lowest_x**2
|
||||
B = -2*coefficient_solution[0][0]*lowest_x
|
||||
self._lowest_y_global = coefficient_solution[0][1]
|
||||
lowest_y = self._lowest_y_global
|
||||
|
||||
# y = A*x**2 + B*x + C
|
||||
# shifting origin to lowest point
|
||||
X = Symbol('X')
|
||||
Y = Symbol('Y')
|
||||
Y = A*(X + lowest_x)**2 + B*(X + lowest_x) + C - lowest_y
|
||||
|
||||
temp_list = list(self._loads['distributed'].values())
|
||||
applied_force = temp_list[0]
|
||||
|
||||
horizontal_force_constant = (applied_force * (self._right_support[0] - lowest_x)**2) / (2 * (self._right_support[1] - lowest_y))
|
||||
|
||||
self._tension.clear()
|
||||
tangent_slope_to_curve = diff(Y, X)
|
||||
self._tension['distributed'] = horizontal_force_constant / (cos(atan(tangent_slope_to_curve)))
|
||||
|
||||
label = self._support_labels[0]
|
||||
self._reaction_loads[Symbol("R_"+label+"_x")] = self.tension_at(self._left_support[0]) * cos(atan(tangent_slope_to_curve.subs(X, self._left_support[0] - lowest_x)))
|
||||
self._reaction_loads[Symbol("R_"+label+"_y")] = self.tension_at(self._left_support[0]) * sin(atan(tangent_slope_to_curve.subs(X, self._left_support[0] - lowest_x)))
|
||||
|
||||
label = self._support_labels[1]
|
||||
self._reaction_loads[Symbol("R_"+label+"_x")] = self.tension_at(self._left_support[0]) * cos(atan(tangent_slope_to_curve.subs(X, self._right_support[0] - lowest_x)))
|
||||
self._reaction_loads[Symbol("R_"+label+"_y")] = self.tension_at(self._left_support[0]) * sin(atan(tangent_slope_to_curve.subs(X, self._right_support[0] - lowest_x)))
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
This method is used to obtain a plot for the specified cable with its supports,
|
||||
shape and loads.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For point loads,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(("A", 0, 10), ("B", 10, 10))
|
||||
>>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270))
|
||||
>>> c.apply_load(-1, ('X', 4, 6, 8, 270))
|
||||
>>> c.solve()
|
||||
>>> p = c.draw()
|
||||
>>> p # doctest: +ELLIPSIS
|
||||
Plot object containing:
|
||||
[0]: cartesian line: Piecewise((10 - 1.37*x, x <= 2), (8.52 - 0.63*x, x <= 4), (2*x/3 + 10/3, x <= 10)) for x over (0.0, 10.0)
|
||||
...
|
||||
>>> p.show()
|
||||
|
||||
For uniformly distributed loads,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c=Cable(("A", 0, 40),("B", 100, 20))
|
||||
>>> c.apply_load(0, ("X", 850))
|
||||
>>> c.solve(58.58)
|
||||
>>> p = c.draw()
|
||||
>>> p # doctest: +ELLIPSIS
|
||||
Plot object containing:
|
||||
[0]: cartesian line: 0.0116550116550117*(x - 58.58)**2 + 0.00447086247086247 for x over (0.0, 100.0)
|
||||
[1]: cartesian line: -7.49552913752915 for x over (0.0, 100.0)
|
||||
...
|
||||
>>> p.show()
|
||||
"""
|
||||
x = Symbol("x")
|
||||
annotations = []
|
||||
support_rectangles = self._draw_supports()
|
||||
|
||||
xy_min = min(self._left_support[0],self._lowest_y_global)
|
||||
xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1]))
|
||||
max_diff = xy_max - xy_min
|
||||
if len(self._loads_position) != 0:
|
||||
self._cable_eqn = self._draw_cable(-1)
|
||||
annotations += self._draw_loads(-1)
|
||||
|
||||
elif len(self._loads['distributed']) != 0 :
|
||||
self._cable_eqn = self._draw_cable(0)
|
||||
annotations += self._draw_loads(0)
|
||||
|
||||
if not self._cable_eqn:
|
||||
raise ValueError("solve method not called and/or values provided for loads and supports not adequate")
|
||||
|
||||
cab_plot = plot(*self._cable_eqn,(x,self._left_support[0],self._right_support[0]),
|
||||
xlim=(xy_min-0.5*max_diff,xy_max+0.5*max_diff),
|
||||
ylim=(xy_min-0.5*max_diff,xy_max+0.5*max_diff),
|
||||
rectangles=support_rectangles,show= False,annotations=annotations, axis=False)
|
||||
|
||||
return cab_plot
|
||||
|
||||
def _draw_supports(self):
|
||||
member_rectangles = []
|
||||
xy_min = min(self._left_support[0],self._lowest_y_global)
|
||||
xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1]))
|
||||
max_diff = xy_max - xy_min
|
||||
|
||||
supp_width = 0.075*max_diff
|
||||
|
||||
member_rectangles.append(
|
||||
{
|
||||
'xy': (self._left_support[0]-supp_width,self._left_support[1]),
|
||||
'width': supp_width,
|
||||
'height':supp_width,
|
||||
'color':'brown',
|
||||
'fill': False
|
||||
}
|
||||
)
|
||||
|
||||
member_rectangles.append(
|
||||
{
|
||||
'xy': (self._right_support[0],self._right_support[1]),
|
||||
'width': supp_width,
|
||||
'height':supp_width,
|
||||
'color':'brown',
|
||||
'fill': False
|
||||
}
|
||||
)
|
||||
|
||||
return member_rectangles
|
||||
|
||||
def _draw_cable(self,order):
|
||||
xy_min = min(self._left_support[0],self._lowest_y_global)
|
||||
xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1]))
|
||||
max_diff = xy_max - xy_min
|
||||
if order == -1 :
|
||||
x,y = symbols('x y')
|
||||
line_func = []
|
||||
sorted_position = sorted(self._loads_position.items(), key = lambda item : item[1][0])
|
||||
|
||||
for i in range(len(sorted_position)):
|
||||
if(i==0):
|
||||
y = ((sorted_position[i][1][1] - self._left_support[1])*(x-self._left_support[0]))/(sorted_position[i][1][0]- self._left_support[0]) + self._left_support[1]
|
||||
else:
|
||||
y = ((sorted_position[i][1][1] - sorted_position[i-1][1][1] )*(x-sorted_position[i-1][1][0]))/(sorted_position[i][1][0]- sorted_position[i-1][1][0]) + sorted_position[i-1][1][1]
|
||||
line_func.append((y,x<=sorted_position[i][1][0]))
|
||||
|
||||
y = ((sorted_position[len(sorted_position)-1][1][1] - self._right_support[1])*(x-self._right_support[0]))/(sorted_position[i][1][0]- self._right_support[0]) + self._right_support[1]
|
||||
line_func.append((y,x<=self._right_support[0]))
|
||||
return [Piecewise(*line_func)]
|
||||
|
||||
elif order == 0:
|
||||
x0 = self._lowest_x_global
|
||||
diff_force_height = max_diff*0.075
|
||||
|
||||
a,c,x,y = symbols('a c x y')
|
||||
parabola_eqn = a*(x-x0)**2 + c - y
|
||||
|
||||
points = [(self._left_support[0],self._left_support[1]),(self._right_support[0],self._right_support[1])]
|
||||
equations = []
|
||||
for px, py in points:
|
||||
equations.append(parabola_eqn.subs({x: px, y: py}))
|
||||
solution = solve(equations, (a, c))
|
||||
parabola_eqn = solution[a]*(x-x0)**2 + solution[c]
|
||||
return [parabola_eqn, self._lowest_y_global - diff_force_height]
|
||||
|
||||
def _draw_loads(self,order):
|
||||
xy_min = min(self._left_support[0],self._lowest_y_global)
|
||||
xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1]))
|
||||
max_diff = xy_max - xy_min
|
||||
if(order==-1):
|
||||
arrow_length = max_diff*0.1
|
||||
force_arrows = []
|
||||
for key in self._loads['point_load']:
|
||||
force_arrows.append(
|
||||
{
|
||||
'text': '',
|
||||
'xy':(self._loads_position[key][0]+arrow_length*cos(rad(self._loads['point_load'][key][1])),\
|
||||
self._loads_position[key][1] + arrow_length*sin(rad(self._loads['point_load'][key][1]))),
|
||||
'xytext': (self._loads_position[key][0],self._loads_position[key][1]),
|
||||
'arrowprops': {'width': 1, 'headlength':3, 'headwidth':3 , 'facecolor': 'black', }
|
||||
}
|
||||
)
|
||||
mag = self._loads['point_load'][key][0]
|
||||
force_arrows.append(
|
||||
{
|
||||
'text':f'{mag}N',
|
||||
'xy': (self._loads_position[key][0]+arrow_length*1.6*cos(rad(self._loads['point_load'][key][1])),\
|
||||
self._loads_position[key][1] + arrow_length*1.6*sin(rad(self._loads['point_load'][key][1]))),
|
||||
}
|
||||
)
|
||||
return force_arrows
|
||||
|
||||
elif (order == 0):
|
||||
x = symbols('x')
|
||||
force_arrows = []
|
||||
x_val = [self._left_support[0] + ((self._right_support[0]-self._left_support[0])/10)*i for i in range(1,10)]
|
||||
for i in x_val:
|
||||
force_arrows.append(
|
||||
{
|
||||
'text':'',
|
||||
'xytext':(
|
||||
i,
|
||||
self._cable_eqn[0].subs(x,i)
|
||||
),
|
||||
'xy':(
|
||||
i,
|
||||
self._cable_eqn[1].subs(x,i)
|
||||
),
|
||||
'arrowprops':{'width':1, 'headlength':3.5, 'headwidth':3.5, 'facecolor':'black'}
|
||||
}
|
||||
)
|
||||
mag = 0
|
||||
for key in self._loads['distributed']:
|
||||
mag += self._loads['distributed'][key]
|
||||
|
||||
force_arrows.append(
|
||||
{
|
||||
'text':f'{mag} N/m',
|
||||
'xy':((self._left_support[0]+self._right_support[0])/2,self._lowest_y_global - max_diff*0.15)
|
||||
}
|
||||
)
|
||||
return force_arrows
|
||||
|
||||
def plot_tension(self):
|
||||
"""
|
||||
Returns the diagram/plot of the tension generated in the cable at various points.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For point loads,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c = Cable(("A", 0, 10), ("B", 10, 10))
|
||||
>>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270))
|
||||
>>> c.apply_load(-1, ('X', 4, 6, 8, 270))
|
||||
>>> c.solve()
|
||||
>>> p = c.plot_tension()
|
||||
>>> p
|
||||
Plot object containing:
|
||||
[0]: cartesian line: Piecewise((8.91403453669861, x <= 2), (4.79150773600774, x <= 4), (19*sqrt(13)/10, x <= 10)) for x over (0.0, 10.0)
|
||||
>>> p.show()
|
||||
|
||||
For uniformly distributed loads,
|
||||
|
||||
>>> from sympy.physics.continuum_mechanics.cable import Cable
|
||||
>>> c=Cable(("A", 0, 40),("B", 100, 20))
|
||||
>>> c.apply_load(0, ("X", 850))
|
||||
>>> c.solve(58.58)
|
||||
>>> p = c.plot_tension()
|
||||
>>> p
|
||||
Plot object containing:
|
||||
[0]: cartesian line: 36465.0*sqrt(0.00054335718671383*X**2 + 1) for X over (0.0, 100.0)
|
||||
>>> p.show()
|
||||
|
||||
"""
|
||||
if len(self._loads_position) != 0:
|
||||
x = symbols('x')
|
||||
tension_plot = plot(self._tension_func, (x,self._left_support[0],self._right_support[0]), show=False)
|
||||
else:
|
||||
X = symbols('X')
|
||||
tension_plot = plot(self._tension['distributed'], (X,self._left_support[0],self._right_support[0]), show=False)
|
||||
return tension_plot
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
from sympy.physics.continuum_mechanics.arch import Arch
|
||||
from sympy import Symbol, simplify
|
||||
|
||||
x = Symbol('x')
|
||||
t = Symbol('t')
|
||||
|
||||
def test_arch_init():
|
||||
a = Arch((0,0),(10,0),crown_x=5,crown_y=5)
|
||||
assert a.get_loads == {'distributed': {}, 'concentrated': {}}
|
||||
assert a.reaction_force == {Symbol('R_A_x'):0, Symbol('R_A_y'):0, Symbol('R_B_x'):0, Symbol('R_B_y'):0}
|
||||
assert a.supports == {'left':'hinge', 'right':'hinge'}
|
||||
assert a.left_support == (0,0)
|
||||
assert a.right_support == (10,0)
|
||||
assert a.get_shape_eqn == 5 - ((x-5)**2)/5
|
||||
|
||||
a = Arch((0,0),(10,1),crown_x=6)
|
||||
a.change_support_type(left_support='roller')
|
||||
a.add_member(0.5)
|
||||
assert a.supports == {'left':'roller', 'right':'hinge'}
|
||||
assert simplify(a.get_shape_eqn) == simplify(9/5 - (x - 6)**2/20)
|
||||
|
||||
def test_arch_support():
|
||||
a = Arch((0,0),(40,0),crown_x=20,crown_y=12)
|
||||
a.apply_load(-1,'C',8,150,angle=270)
|
||||
a.apply_load(0,'D',start=20,end=40,mag=-4)
|
||||
a.solve()
|
||||
assert abs(a.reaction_force[Symbol("R_A_x")] - 83.33333333333333) < 10e-12
|
||||
assert abs(a.reaction_force[Symbol("R_B_y")] - 90.00000000000000) < 10e-12
|
||||
assert abs(a.reaction_force[Symbol("R_B_x")] + 83.33333333333333) < 10e-12
|
||||
assert abs(a.reaction_force[Symbol("R_A_y")] - 140.00000000000000) < 10e-12
|
||||
|
||||
def test_arch_member():
|
||||
a = Arch((0,0),(40,0),crown_x=20,crown_y=15)
|
||||
a.change_support_type(right_support='roller')
|
||||
a.add_member(0)
|
||||
a.apply_load(-1,'D',start=12,mag=3,angle=270)
|
||||
a.apply_load(-1,'E',start=6,mag=4,angle=270)
|
||||
a.apply_load(-1,'C',start=30,mag=5,angle=270)
|
||||
a.solve()
|
||||
assert a.reaction_force[Symbol("R_A_x")] == 0
|
||||
assert abs(a.reaction_force[Symbol("R_A_y")] - 6.750000000000000) < 10e-12
|
||||
assert a.reaction_force[Symbol("R_B_x")] == 0
|
||||
assert abs(a.reaction_force[Symbol("R_B_y")] - 5.250000000000000) < 10e-12
|
||||
|
||||
def test_symbol_magnitude():
|
||||
a = Arch((0,0),(16,0),crown_x=8,crown_y=5)
|
||||
a.apply_load(0,'C',start=3,end=5,mag=t)
|
||||
a.solve()
|
||||
assert a.reaction_force[Symbol("R_A_x")] == -(4*t)/5
|
||||
assert a.reaction_force[Symbol("R_A_y")] == -(3*t)/2
|
||||
assert a.reaction_force[Symbol("R_B_x")] == (4*t)/5
|
||||
assert a.reaction_force[Symbol("R_B_y")] == -t/2
|
||||
assert a.bending_moment_at(4) == -5*t/2
|
||||
|
||||
def test_forces():
|
||||
a = Arch((0,0),(40,0),crown_x=20,crown_y=12)
|
||||
a.apply_load(-1,'C',8,150,angle=270)
|
||||
a.apply_load(0,'D',start=20,end=40,mag=-4)
|
||||
a.solve()
|
||||
assert abs(a.axial_force_at(7.999999999999999)-149.430523405935) < 1e-12
|
||||
assert abs(a.shear_force_at(7.999999999999999)-64.9227473161196) < 1e-12
|
||||
+1118
File diff suppressed because it is too large
Load Diff
+83
@@ -0,0 +1,83 @@
|
||||
from sympy.physics.continuum_mechanics.cable import Cable
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
|
||||
def test_cable():
|
||||
c = Cable(('A', 0, 10), ('B', 10, 10))
|
||||
assert c.supports == {'A': [0, 10], 'B': [10, 10]}
|
||||
assert c.left_support == [0, 10]
|
||||
assert c.right_support == [10, 10]
|
||||
assert c.loads == {'distributed': {}, 'point_load': {}}
|
||||
assert c.loads_position == {}
|
||||
assert c.length == 0
|
||||
assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0}
|
||||
|
||||
# tests for change_support method
|
||||
c.change_support('A', ('C', 12, 3))
|
||||
assert c.supports == {'B': [10, 10], 'C': [12, 3]}
|
||||
assert c.left_support == [10, 10]
|
||||
assert c.right_support == [12, 3]
|
||||
assert c.reaction_loads == {Symbol("R_B_x"): 0, Symbol("R_B_y"): 0, Symbol("R_C_x"): 0, Symbol("R_C_y"): 0}
|
||||
|
||||
c.change_support('C', ('A', 0, 10))
|
||||
|
||||
# tests for apply_load method for point loads
|
||||
c.apply_load(-1, ('X', 2, 5, 3, 30))
|
||||
c.apply_load(-1, ('Y', 5, 8, 5, 60))
|
||||
assert c.loads == {'distributed': {}, 'point_load': {'X': [3, 30], 'Y': [5, 60]}}
|
||||
assert c.loads_position == {'X': [2, 5], 'Y': [5, 8]}
|
||||
assert c.length == 0
|
||||
assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0}
|
||||
|
||||
# tests for remove_loads method
|
||||
c.remove_loads('X')
|
||||
assert c.loads == {'distributed': {}, 'point_load': {'Y': [5, 60]}}
|
||||
assert c.loads_position == {'Y': [5, 8]}
|
||||
assert c.length == 0
|
||||
assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0}
|
||||
|
||||
c.remove_loads('Y')
|
||||
|
||||
#tests for apply_load method for distributed load
|
||||
c.apply_load(0, ('Z', 9))
|
||||
assert c.loads == {'distributed': {'Z': 9}, 'point_load': {}}
|
||||
assert c.loads_position == {}
|
||||
assert c.length == 0
|
||||
assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0}
|
||||
|
||||
# tests for apply_length method
|
||||
c.apply_length(20)
|
||||
assert c.length == 20
|
||||
|
||||
del c
|
||||
# tests for solve method
|
||||
# for point loads
|
||||
c = Cable(("A", 0, 10), ("B", 5.5, 8))
|
||||
c.apply_load(-1, ('Z', 2, 7.26, 3, 270))
|
||||
c.apply_load(-1, ('X', 4, 6, 8, 270))
|
||||
c.solve()
|
||||
#assert c.tension == {Symbol("Z_X"): 4.79150773600774, Symbol("X_B"): 6.78571428571429, Symbol("A_Z"): 6.89488895397307}
|
||||
assert abs(c.tension[Symbol("A_Z")] - 6.89488895397307) < 10e-12
|
||||
assert abs(c.tension[Symbol("Z_X")] - 4.79150773600774) < 10e-12
|
||||
assert abs(c.tension[Symbol("X_B")] - 6.78571428571429) < 10e-12
|
||||
#assert c.reaction_loads == {Symbol("R_A_x"): -4.06504065040650, Symbol("R_A_y"): 5.56910569105691, Symbol("R_B_x"): 4.06504065040650, Symbol("R_B_y"): 5.43089430894309}
|
||||
assert abs(c.reaction_loads[Symbol("R_A_x")] + 4.06504065040650) < 10e-12
|
||||
assert abs(c.reaction_loads[Symbol("R_A_y")] - 5.56910569105691) < 10e-12
|
||||
assert abs(c.reaction_loads[Symbol("R_B_x")] - 4.06504065040650) < 10e-12
|
||||
assert abs(c.reaction_loads[Symbol("R_B_y")] - 5.43089430894309) < 10e-12
|
||||
assert abs(c.length - 8.25609584845190) < 10e-12
|
||||
|
||||
del c
|
||||
# tests for solve method
|
||||
# for distributed loads
|
||||
c=Cable(("A", 0, 40),("B", 100, 20))
|
||||
c.apply_load(0, ("X", 850))
|
||||
c.solve(58.58, 0)
|
||||
|
||||
# assert c.tension['distributed'] == 36456.8485*sqrt(0.000543529004799705*(X + 0.00135624381275735)**2 + 1)
|
||||
assert abs(c.tension_at(0) - 61717.4130533677) < 10e-11
|
||||
assert abs(c.tension_at(40) - 39738.0809048449) < 10e-11
|
||||
assert abs(c.reaction_loads[Symbol("R_A_x")] - 36465.0000000000) < 10e-11
|
||||
assert abs(c.reaction_loads[Symbol("R_A_y")] + 49793.0000000000) < 10e-11
|
||||
assert abs(c.reaction_loads[Symbol("R_B_x")] - 44399.9537590861) < 10e-11
|
||||
assert abs(c.reaction_loads[Symbol("R_B_y")] - 42868.2071025955 ) < 10e-11
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
from sympy.core.symbol import Symbol, symbols
|
||||
from sympy.physics.continuum_mechanics.truss import Truss
|
||||
from sympy import sqrt
|
||||
|
||||
|
||||
def test_truss():
|
||||
A = Symbol('A')
|
||||
B = Symbol('B')
|
||||
C = Symbol('C')
|
||||
AB, BC, AC = symbols('AB, BC, AC')
|
||||
P = Symbol('P')
|
||||
|
||||
t = Truss()
|
||||
assert t.nodes == []
|
||||
assert t.node_labels == []
|
||||
assert t.node_positions == []
|
||||
assert t.members == {}
|
||||
assert t.loads == {}
|
||||
assert t.supports == {}
|
||||
assert t.reaction_loads == {}
|
||||
assert t.internal_forces == {}
|
||||
|
||||
# testing the add_node method
|
||||
t.add_node((A, 0, 0), (B, 2, 2), (C, 3, 0))
|
||||
assert t.nodes == [(A, 0, 0), (B, 2, 2), (C, 3, 0)]
|
||||
assert t.node_labels == [A, B, C]
|
||||
assert t.node_positions == [(0, 0), (2, 2), (3, 0)]
|
||||
assert t.loads == {}
|
||||
assert t.supports == {}
|
||||
assert t.reaction_loads == {}
|
||||
|
||||
# testing the remove_node method
|
||||
t.remove_node(C)
|
||||
assert t.nodes == [(A, 0, 0), (B, 2, 2)]
|
||||
assert t.node_labels == [A, B]
|
||||
assert t.node_positions == [(0, 0), (2, 2)]
|
||||
assert t.loads == {}
|
||||
assert t.supports == {}
|
||||
|
||||
t.add_node((C, 3, 0))
|
||||
|
||||
# testing the add_member method
|
||||
t.add_member((AB, A, B), (BC, B, C), (AC, A, C))
|
||||
assert t.members == {AB: [A, B], BC: [B, C], AC: [A, C]}
|
||||
assert t.internal_forces == {AB: 0, BC: 0, AC: 0}
|
||||
|
||||
# testing the remove_member method
|
||||
t.remove_member(BC)
|
||||
assert t.members == {AB: [A, B], AC: [A, C]}
|
||||
assert t.internal_forces == {AB: 0, AC: 0}
|
||||
|
||||
t.add_member((BC, B, C))
|
||||
|
||||
D, CD = symbols('D, CD')
|
||||
|
||||
# testing the change_label methods
|
||||
t.change_node_label((B, D))
|
||||
assert t.nodes == [(A, 0, 0), (D, 2, 2), (C, 3, 0)]
|
||||
assert t.node_labels == [A, D, C]
|
||||
assert t.loads == {}
|
||||
assert t.supports == {}
|
||||
assert t.members == {AB: [A, D], BC: [D, C], AC: [A, C]}
|
||||
|
||||
t.change_member_label((BC, CD))
|
||||
assert t.members == {AB: [A, D], CD: [D, C], AC: [A, C]}
|
||||
assert t.internal_forces == {AB: 0, CD: 0, AC: 0}
|
||||
|
||||
|
||||
# testing the apply_load method
|
||||
t.apply_load((A, P, 90), (A, P/4, 90), (A, 2*P,45), (D, P/2, 90))
|
||||
assert t.loads == {A: [[P, 90], [P/4, 90], [2*P, 45]], D: [[P/2, 90]]}
|
||||
assert t.loads[A] == [[P, 90], [P/4, 90], [2*P, 45]]
|
||||
|
||||
# testing the remove_load method
|
||||
t.remove_load((A, P/4, 90))
|
||||
assert t.loads == {A: [[P, 90], [2*P, 45]], D: [[P/2, 90]]}
|
||||
assert t.loads[A] == [[P, 90], [2*P, 45]]
|
||||
|
||||
# testing the apply_support method
|
||||
t.apply_support((A, "pinned"), (D, "roller"))
|
||||
assert t.supports == {A: 'pinned', D: 'roller'}
|
||||
assert t.reaction_loads == {}
|
||||
assert t.loads == {A: [[P, 90], [2*P, 45], [Symbol('R_A_x'), 0], [Symbol('R_A_y'), 90]], D: [[P/2, 90], [Symbol('R_D_y'), 90]]}
|
||||
|
||||
# testing the remove_support method
|
||||
t.remove_support(A)
|
||||
assert t.supports == {D: 'roller'}
|
||||
assert t.reaction_loads == {}
|
||||
assert t.loads == {A: [[P, 90], [2*P, 45]], D: [[P/2, 90], [Symbol('R_D_y'), 90]]}
|
||||
|
||||
t.apply_support((A, "pinned"))
|
||||
|
||||
# testing the solve method
|
||||
t.solve()
|
||||
assert t.reaction_loads['R_A_x'] == -sqrt(2)*P
|
||||
assert t.reaction_loads['R_A_y'] == -sqrt(2)*P - P
|
||||
assert t.reaction_loads['R_D_y'] == -P/2
|
||||
assert t.internal_forces[AB]/P == 0
|
||||
assert t.internal_forces[CD] == 0
|
||||
assert t.internal_forces[AC] == 0
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user