In [1]:
from __future__ import division, print_function
import numpy as np
import matplotlib.pyplot as plt
import solidspy.postprocesor as pos
import solidspy.assemutil as ass
import solidspy.solutil as sol
import solidspy.uelutil as uel
In [2]:
% matplotlib notebook
The problem of interest is represented in the following image,
the section of each bar is $A = \frac{1}{100}\text{ m}^2$ and the Young modulus $E = 10^6\text{ Pa}$.
First, let's define the nodes array for this problem. Each row is of the form
node_id coord_x coord_y cons_x cons_y
where:
node_id
: is the node identifier;coord_x
: is the $x$ coordinate of the node;coord_y
: is the $y$ coordinate of the node;cons_x
: tells us if the node is constrained in the $x$ direction;cons_y
: tells us if the node is constrained in $y$;-1 means constrained and 0 unconstrained.
In [3]:
nodes = np.array([
[0, 10*np.sqrt(3)/2, 0.0, 0, 0],
[1, 0.0, 5.0, -1, 0],
[2, 0.0, 0.0, -1, -1]])
In [4]:
mats = np.array([
[1e6, 0.01],
[1e6, 0.01],
[1e6, 0.01]])
The elements array provide the connectivity between nodes, material profile, and type of element for each element. The form for each row is
el_id el_type mat_profile node_ini node_end
where:
el_id
: element identifier;el_type
: element type (6 for truss elements);mat_profile
: material profile, in this case we have one material profile
for each element;node_ini
: first node of the bar;node_end
: last node of the bar.
In [5]:
eles = np.array([
[0, 6, 0, 2, 0],
[1, 6, 1, 0, 1],
[2, 6, 2, 1, 2]])
In [6]:
loads = np.array([
[0, 0.0, -10.0],
[1, 0.0, 0.0]])
Now, let's plot a graphic of the truss given by our arrays to double-check.
In [7]:
def plot_truss(nodes, elements, mats, color="green"):
"""
Plot a truss
"""
areas = mats[:, 1]
min_area = areas.min()
max_area = areas.max()
max_val = 4
min_val = 0.5
if max_area - min_area > 1e-6:
widths = (max_val - min_val)*(areas - min_area)/(max_area - min_area)\
+ min_val
else:
widths = 3*np.ones_like(areas)
for el in elements:
ini, end = el[3:]
plt.plot([nodes[ini, 1], nodes[end, 1]],
[nodes[ini, 2], nodes[end, 2]],
color=color, lw=widths[el[2]])
plt.axis("image")
In [9]:
plt.figure()
plot_truss(nodes, eles, mats, color="green");
The first step to solve the problem is to compute the stiffness matrices for each member of the truss in global coordinates. These matrices are given by
$$K_0 = \frac{2000}{\sqrt{3}}\begin{bmatrix} 1 &0 &-1 &0\\ 0 &0 &0 &0\\ 1 &0 &-1 &0\\ 0 &0 &0 &0\end{bmatrix}$$$$K_1 = 250\begin{bmatrix} 3 &-\sqrt{3} &-3 &\sqrt{3}\\ \sqrt{3} &1 &\sqrt{3} &-1\\ -3 &\sqrt{3} &3 &-\sqrt{3}\\ \sqrt{3} &-1 &-\sqrt{3} &1\end{bmatrix}$$$$K_2 = 2000\begin{bmatrix} 0 &0 &0 &0\\ 0 &1 &0 &1\\ 0 &0 &0 &0\\ 0 &-1 &0 &1\end{bmatrix}$$We can double-check that this result is correct printing the matrices
returned by uel.ueltruss2D
from solidspy
.
In [10]:
for cont in range(3):
Kloc = uel.ueltruss2D(nodes[eles[cont, 3:], 1:3], *mats[cont, :])
print("Element {}\n".format(cont), np.round(Kloc))
Once we have the elemental matrices we can form the global system of equations to obtain the global matrix.
Let's consider, for now, that none of the nodes is contrained. From a physics point of view, that might be unsound, since that would render the problem undetermined. We will solve that problem later on.
The global matrix (for unconstrained nodes) is
$$K_\text{total} = 250 \begin{bmatrix} \frac{8}{\sqrt{3}} + 3 &-\sqrt{3} &3 &\sqrt{3} &-\frac{8}{\sqrt{3}} &0\\ -\sqrt{3} &1 &\sqrt{3} &-1 &0 &0\\ 3 &\sqrt{3} &3 &-\sqrt{3} &0 &0\\ \sqrt{3} &-1 &-\sqrt{3} &9 &0 &-8\\ -\frac{8}{\sqrt{3}} &0 &0 &0 &\frac{8}{\sqrt{3}} &0\\ 0 &0 &0 &-8 &0 &8 \end{bmatrix}$$To check that step we can use the solidspy
as well, considering a different
nodes array.
In [11]:
nodes_uncon = np.array([
[0, 10*np.sqrt(3)/2, 0.0, 0, 0],
[1, 0.0, 5.0, 0, 0],
[2, 0.0, 0.0, 0, 0]])
DME , IBC , neq = ass.DME(nodes_uncon, eles)
KG_uncon = ass.assembler(eles, mats, nodes_uncon, neq, DME, sparse=False)
print(np.round(KG_uncon))
In our problem, we are interested in the constrained stiffness matrix. First, because the underlying system of equations has a unique solution. Second, because that would make it smaller.
The constrained matrix is the following
$$K_\text{total}^\text{cons} = 250 \begin{bmatrix} \frac{8}{\sqrt{3}} + 3 &-\sqrt{3} &\sqrt{3}\\ -\sqrt{3} &1 &-1 \\ \sqrt{3} &-1 &9\\ \end{bmatrix}$$We can check that result with solidspy
as well.
In [12]:
# System assembly
DME , IBC , neq = ass.DME(nodes, eles)
stiff = ass.assembler(eles, mats, nodes, neq, DME, sparse=False)
load_vec = ass.loadasem(loads, IBC, neq) # right-hand-side
In [13]:
print(np.round(stiff))
In [14]:
print(load_vec)
In [15]:
# System solution
disp = sol.static_sol(stiff, load_vec)
disp
Out[15]:
In [16]:
# Post-processing
disp_complete = pos.complete_disp(IBC, nodes, disp)
disp_complete
Out[16]:
In [ ]:
In [16]:
from IPython.core.display import HTML
def css_styling():
styles = open('../custom_barba.css', 'r').read()
return HTML(styles)
css_styling()
Out[16]: