M = np.zeros((DOF * nx, DOF * nx)) elems = [] # creating beam elements nids = list(nid_pos.keys()) for n1, n2 in zip(nids[:-1], nids[1:]): elem = Beam2D() elem.n1 = n1 elem.n2 = n2 elem.E = E elem.A1 = elem.A2 = A elem.Izz1 = elem.Izz2 = Izz elem.rho = rho elem.interpolation = 'legendre' update_K(elem, nid_pos, ncoords, K) update_M(elem, nid_pos, M, lumped=lumped) elems.append(elem) if lumped: assert np.count_nonzero(M - np.diag(np.diagonal(M))) == 0 # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) # defining known DOFs check = np.isclose(x, 0.) bk[0::DOF] = check bk[1::DOF] = check bk[2::DOF] = check bu = ~bk # defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu]
def test_beam2d_displ(plot=False): # number of nodes n = 2 # Material Lastrobe Lescalloy E = 203.e9 # Pa F = -7000 rho = 7.83e3 # kg/m3 L = 3 x = np.linspace(0, L, n) y = np.zeros_like(x) # tapered properties b_root = 0.05 # m b_tip = b_root # m h_root = 0.05 # m h_tip = h_root # m A_root = h_root * b_root A_tip = h_tip * b_tip Izz_root = b_root * h_root**3 / 12 Izz_tip = b_tip * h_tip**3 / 12 # getting nodes ncoords = np.vstack((x, y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3 * n, 3 * n)) M = np.zeros((3 * n, 3 * n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A2 = A_root Izz1 = Izz2 = Izz_root beam = Beam2D() beam.interpolation = 'legendre' beam.n1 = n1 beam.n2 = n2 # Material Lastrobe Lescalloy beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, 0.) # locating node at root # clamping at root for i in range(DOF): bk[i::DOF] = check bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # test f = np.zeros(K.shape[0]) f[-2] = F fu = f[bu] # solving uu = solve(Kuu, fu) # vector u containing displacements for all DOFs u = np.zeros(K.shape[0], dtype=float) u[bu] = uu beam = beams[0] nplot = 100 xplot = np.linspace(0, L, nplot) yplot = np.zeros_like(xplot) uinterp, vinterp = uv(beam, *u[:6], n=nplot) assert np.allclose(vinterp[0], [ 0.00000000e+00, -9.08870216e-05, -3.62319884e-04, -8.12456281e-04, -1.43945391e-03, -2.24147047e-03, -3.21666364e-03, -4.36319114e-03, -5.67921065e-03, -7.16287987e-03, -8.81235649e-03, -1.06257982e-02, -1.26013627e-02, -1.47372077e-02, -1.70314909e-02, -1.94823700e-02, -2.20880027e-02, -2.48465466e-02, -2.77561595e-02, -3.08149990e-02, -3.40212230e-02, -3.73729889e-02, -4.08684547e-02, -4.45057778e-02, -4.82831161e-02, -5.21986273e-02, -5.62504690e-02, -6.04367989e-02, -6.47557747e-02, -6.92055542e-02, -7.37842949e-02, -7.84901547e-02, -8.33212912e-02, -8.82758621e-02, -9.33520250e-02, -9.85479378e-02, -1.03861758e-01, -1.09291644e-01, -1.14835752e-01, -1.20492241e-01, -1.26259268e-01, -1.32134991e-01, -1.38117568e-01, -1.44205156e-01, -1.50395913e-01, -1.56687997e-01, -1.63079565e-01, -1.69568776e-01, -1.76153786e-01, -1.82832754e-01, -1.89603837e-01, -1.96465193e-01, -2.03414980e-01, -2.10451355e-01, -2.17572476e-01, -2.24776501e-01, -2.32061587e-01, -2.39425892e-01, -2.46867574e-01, -2.54384790e-01, -2.61975699e-01, -2.69638457e-01, -2.77371223e-01, -2.85172155e-01, -2.93039409e-01, -3.00971144e-01, -3.08965517e-01, -3.17020687e-01, -3.25134810e-01, -3.33306044e-01, -3.41532548e-01, -3.49812478e-01, -3.58143993e-01, -3.66525251e-01, -3.74954408e-01, -3.83429623e-01, -3.91949053e-01, -4.00510856e-01, -4.09113189e-01, -4.17754212e-01, -4.26432080e-01, -4.35144952e-01, -4.43890985e-01, -4.52668338e-01, -4.61475168e-01, -4.70309632e-01, -4.79169888e-01, -4.88054095e-01, -4.96960409e-01, -5.05886988e-01, -5.14831990e-01, -5.23793574e-01, -5.32769895e-01, -5.41759113e-01, -5.50759384e-01, -5.59768868e-01, -5.68785720e-01, -5.77808099e-01, -5.86834163e-01, -5.95862069e-01 ]) if plot: # plotting import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.gca().set_aspect('equal') plt.plot(x, y, '-k') plt.plot(xplot + uinterp[0], yplot + vinterp[0], '--r') plt.show()
pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A[nid_pos[n1]] A2 = A[nid_pos[n2]] Izz1 = Izz[nid_pos[n1]] Izz2 = Izz[nid_pos[n2]] beam = Beam2D() beam.n1 = n1 beam.n2 = n2 beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M, lumped=False) elements.append(beam) I = np.ones_like(M) # applying boundary conditions # uroot = 0 # vroot = unknown # betaroot = 0 # utip = unknown # vtip = prescribed displacement # betatip = unknown known_ind = [0, 2, (K.shape[0] - 1) - 1] bu = np.logical_not(np.in1d(np.arange(M.shape[0]), known_ind)) bk = np.in1d(np.arange(M.shape[0]), known_ind)
pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A[nid_pos[n1]] A2 = A[nid_pos[n2]] Izz1 = Izz[nid_pos[n1]] Izz2 = Izz[nid_pos[n2]] beam = Beam2D() beam.n1 = n1 beam.n2 = n2 beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M, lumped=True) elements.append(beam) I = np.ones_like(M) # applying boundary conditions # uroot = 0 # vroot = unknown # betaroot = 0 # utip = unknown # vtip = prescribed displacement # betatip = unknown known_ind = [0, 2, (K.shape[0] - 1) - 1] bu = np.logical_not(np.in1d(np.arange(M.shape[0]), known_ind)) bk = np.in1d(np.arange(M.shape[0]), known_ind)
def test_nat_freq_cantilever_beam(plot=False, mode=0): n = 100 L = 3 # total size of the beam along x # Material Lastrobe Lescalloy E = 203.e9 # Pa rho = 7.83e3 # kg/m3 x = np.linspace(0, L, n) # path y = np.ones_like(x) # tapered properties b = 0.05 # m h = 0.05 # m A = h * b Izz = b * h**3 / 12 # getting nodes ncoords = np.vstack((x, y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3 * n, 3 * n)) M = np.zeros((3 * n, 3 * n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A2 = A Izz1 = Izz2 = Izz beam = Beam2D() beam.n1 = n1 beam.n2 = n2 beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, 0.) # locating node at root # clamping at root for i in range(DOF): bk[i::DOF] = check bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] eigvals, U = eigh(a=Kuu, b=Muu) omegan = eigvals**0.5 # vector u containing displacements for all DOFs u = np.zeros(K.shape[0], dtype=float) u[bu] = U[:, mode] # reference answer alpha123 = np.array([1.875, 4.694, 7.885]) omega123 = alpha123**2 * np.sqrt(E * Izz / (rho * A * L**4)) print('Theoretical omega123', omega123) print('Numerical omega123', omegan[0:3]) assert np.allclose(omega123, omegan[0:3], rtol=0.01) if plot: # plotting import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.plot(x, y, '-k') plt.plot(x + u[0::DOF], y + u[1::DOF], '--r') plt.show()
M = np.zeros((DOF * nx, DOF * nx)) elems = [] # creating beam elements nids = list(nid_pos.keys()) for n1, n2 in zip(nids[:-1], nids[1:]): elem = Beam2D() elem.n1 = n1 elem.n2 = n2 elem.E = E elem.A1 = elem.A2 = A elem.Izz1 = elem.Izz2 = Izz elem.rho = rho elem.interpolation = 'legendre' update_K(elem, nid_pos, ncoords, K) update_M(elem, nid_pos, M) elems.append(elem) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) # defining known DOFs check = np.isclose(x, 0.) bk[0::DOF] = check bk[1::DOF] = check bk[2::DOF] = check bu = ~bk # defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # solving
def test_beam2d_displ(plot=False): # number of nodes n = 2 # Material Lastrobe Lescalloy E = 203.e9 # Pa F = -7000 rho = 7.83e3 # kg/m3 L = 3 x = np.linspace(0, L, n) y = np.zeros_like(x) # tapered properties b_root = 0.05 # m b_tip = b_root # m h_root = 0.05 # m h_tip = h_root # m A_root = h_root*b_root A_tip = h_tip*b_tip Izz_root = b_root*h_root**3/12 Izz_tip = b_tip*h_tip**3/12 # getting nodes ncoords = np.vstack((x ,y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3*n, 3*n)) M = np.zeros((3*n, 3*n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A2 = A_root Izz1 = Izz2 = Izz_root beam = Beam2D() beam.interpolation = 'legendre' beam.n1 = n1 beam.n2 = n2 # Material Lastrobe Lescalloy beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, 0.) # locating node at root # clamping at root for i in range(DOF): bk[i::DOF] = check bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # test f = np.zeros(K.shape[0]) f[-2] = F fu = f[bu] # solving uu = solve(Kuu, fu) # vector u containing displacements for all DOFs u = np.zeros(K.shape[0], dtype=float) u[bu] = uu beam = beams[0] nplot = 10 xplot = np.linspace(0, L, nplot) yplot = np.zeros_like(xplot) h = np.linspace(h_root, h_tip, nplot) exxbot = exx(-h/2, beam, *u[:6], n=nplot) exxtop = exx(+h/2, beam, *u[:6], n=nplot) ref = np.array([-0.00496552, -0.00441379, -0.00386207, -0.00331034, -0.00275862, -0.0022069, -0.00165517, -0.00110345, -0.00055172, 0.]) assert np.allclose(exxbot[0], ref) assert np.allclose(exxtop[0], -ref) if plot: # plotting import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.plot(xplot, exxbot[0]) plt.plot(xplot, exxtop[0]) plt.show()
def test_static_curved_beam(plot=False): # number of nodes n = 24 # Material Lastrobe Lescalloy E = 203.e9 # Pa F = 7000 rho = 7.83e3 # kg/m3 thetas = np.linspace(np.pi / 2, 0, n) radius = 1.2 x = radius * np.cos(thetas) y = -1.2 + radius * np.sin(thetas) # path print('y_tip', y[-1]) # tapered properties b_root = 0.05 # m b_tip = b_root # m h_root = 0.05 # m h_tip = h_root # m A_root = h_root * b_root A_tip = h_tip * b_tip Izz_root = b_root * h_root**3 / 12 Izz_tip = b_tip * h_tip**3 / 12 # getting nodes ncoords = np.vstack((x, y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3 * n, 3 * n)) M = np.zeros((3 * n, 3 * n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A2 = A_root Izz1 = Izz2 = Izz_root beam = Beam2D() beam.interpolation = 'legendre' beam.n1 = n1 beam.n2 = n2 # Material Lastrobe Lescalloy beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, x.min()) # clamping curved beam at the left extremity for i in range(DOF): bk[i::DOF] = check bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # test f = np.zeros(K.shape[0]) f[-2] = F fu = f[bu] # solving uu = solve(Kuu, fu) # vector u containing displacements for all DOFs u = np.zeros(K.shape[0], dtype=float) u[bu] = uu u = u.reshape(n, -1) print('u_tip', u[-1]) ref_from_Abaqus = 5.738e-2, 4.064e-2 print('Reference from Abaqus: u_tip', ref_from_Abaqus) assert np.allclose(u[-1, 0:2], ref_from_Abaqus, rtol=0.01) if plot: # plotting import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.gca().set_aspect('equal') plt.plot(x, y, '-k') plt.plot(x + u[:, 0], y + u[:, 1], '--r') plt.show()
def test_cantilever_beam(plot=False): n = 100 L = 3 # total size of the beam along x # Material Lastrobe Lescalloy E = 203.e9 # Pa rho = 7.83e3 # kg/m3 x = np.linspace(0, L, n) # path y = np.ones_like(x) # tapered properties b_root = 0.05 # m b_tip = b_root # m h_root = 0.05 # m h_tip = h_root # m A_root = h_root * b_root A_tip = h_tip * b_tip Izz_root = b_root * h_root**3 / 12 Izz_tip = b_tip * h_tip**3 / 12 # getting nodes ncoords = np.vstack((x, y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3 * n, 3 * n)) M = np.zeros((3 * n, 3 * n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A_root + (A_tip - A_root) * x1 * A_tip / (L - 0) A2 = A_root + (A_tip - A_root) * x2 * A_tip / (L - 0) Izz1 = Izz_root + (Izz_tip - Izz_root) * x1 * Izz_tip / (L - 0) Izz2 = Izz_root + (Izz_tip - Izz_root) * x2 * Izz_tip / (L - 0) beam = Beam2D() beam.n1 = n1 beam.n2 = n2 beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, 0.) # locating node at root # clamping at root for i in range(DOF): bk[i::DOF] = check bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # test Fy = 700 f = np.zeros(K.shape[0]) f[-2] = Fy fu = f[bu] # solving uu = solve(Kuu, fu) # vector u containing displacements for all DOFs u = np.zeros(K.shape[0], dtype=float) u[bu] = uu u = u.reshape(n, -1) a = L deflection = Fy * a**3 / (3 * E * Izz_root) * (1 + 3 * (L - a) / 2 * a) print('Theoretical deflection', deflection) print('Numerical deflection', u[-1, 1]) assert np.isclose(deflection, u[-1, 1]) if plot: # plotting import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.plot(x, y, '-k') plt.plot(x + u[:, 0], y + u[:, 1], '--r') plt.show()
def test_nat_freq_curved_beam(): n = 100 # comparing with: # https://www.sciencedirect.com/science/article/pii/S0168874X06000916 # see section 5.4 E = 206.8e9 # Pa rho = 7855 # kg/m3 A = 4.071e-3 Izz = 6.456e-6 thetabeam = np.deg2rad(97) r = 2.438 thetas = np.linspace(0, thetabeam, n) x = r * np.cos(thetas) y = r * np.sin(thetas) # getting nodes ncoords = np.vstack((x, y)).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) n1s = nids[0:-1] n2s = nids[1:] K = np.zeros((3 * n, 3 * n)) M = np.zeros((3 * n, 3 * n)) beams = [] for n1, n2 in zip(n1s, n2s): pos1 = nid_pos[n1] pos2 = nid_pos[n2] x1, y1 = ncoords[pos1] x2, y2 = ncoords[pos2] A1 = A2 = A Izz1 = Izz2 = Izz beam = Beam2D() beam.n1 = n1 beam.n2 = n2 beam.E = E beam.rho = rho beam.A1, beam.A2 = A1, A2 beam.Izz1, beam.Izz2 = Izz1, Izz2 update_K(beam, nid_pos, ncoords, K) update_M(beam, nid_pos, M) beams.append(beam) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) #array to store known DOFs check = np.isclose(x, x.min()) | np.isclose( x, x.max()) # locating nodes at both ends # simply supporting at both ends bk[0::DOF] = check # u bk[1::DOF] = check # v bu = ~bk # same as np.logical_not, defining unknown DOFs # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] eigvals, U = eigh(a=Kuu, b=Muu) omegan = eigvals**0.5 omega123 = [396.98, 931.22, 1797.31] print('Reference omega123', omega123) print('Numerical omega123', omegan[0:3]) assert np.allclose(omega123, omegan[0:3], rtol=0.01)