def test_calc_linear_buckling(): E11 = 71.e9 nu = 0.33 plyt = 0.007 lam = read_stack([0], plyt=plyt, laminaprop=(E11, E11, nu)) ans = { 'edge-based': 41.85273, 'cell-based': 6.98852939, 'cell-based-no-smoothing': 4.921956 } for prop_from_nodes in [True, False]: for k0s_method in [ 'edge-based', 'cell-based', 'cell-based-no-smoothing' ]: mesh = read_mesh( os.path.join(THISDIR, 'nastran_plate_16_nodes.dat')) for tria in mesh.elements.values(): tria.prop = lam for node in mesh.nodes.values(): node.prop = lam k0 = calc_k0(mesh, prop_from_nodes) add_k0s(k0, mesh, prop_from_nodes, k0s_method, alpha=0.2) # running static subcase first dof = 5 n = k0.shape[0] // 5 fext = np.zeros(n * dof, dtype=np.float64) fext[mesh.nodes[4].index * dof + 0] = -500. fext[mesh.nodes[7].index * dof + 0] = -500. fext[mesh.nodes[5].index * dof + 0] = -1000. fext[mesh.nodes[6].index * dof + 0] = -1000. # boundary conditions def bc(K): for i in [1, 10, 11, 12]: for j in [0, 1, 2]: K[mesh.nodes[i].index * dof + j, :] = 0 K[:, mesh.nodes[i].index * dof + j] = 0 for i in [2, 3, 4, 5, 6, 7, 8, 9]: for j in [1, 2]: K[mesh.nodes[i].index * dof + j, :] = 0 K[:, mesh.nodes[i].index * dof + j] = 0 bc(k0) k0 = coo_matrix(k0) d = solve(k0, fext, silent=True) kG = calc_kG(d, mesh, prop_from_nodes) bc(kG) kG = coo_matrix(kG) eigvals, eigvecs = lb(k0, kG, silent=True) print('k0s_method, eigvals[0]', k0s_method, eigvals[0]) assert np.isclose(eigvals[0], ans[k0s_method])
def test_calc_linear_static(): mesh = read_mesh(os.path.join(THISDIR, 'nastran_plate_16_nodes.dat')) E11 = 71.e9 nu = 0.33 plyt = 0.007 lam = read_stack([0], plyt=plyt, laminaprop=(E11, E11, nu)) for tria in mesh.elements.values(): tria.prop = lam for node in mesh.nodes.values(): node.prop = lam for prop_from_nodes in [False, True]: for k0s_method in ['cell-based', 'cell-based-no-smoothing']: #, 'edge-based' k0 = calc_k0(mesh, prop_from_nodes) add_k0s(k0, mesh, prop_from_nodes, k0s_method, alpha=0.2) k0run = k0.copy() dof = 5 n = k0.shape[0] // dof fext = np.zeros(n*dof, dtype=np.float64) fext[mesh.nodes[4].index*dof + 2] = 500. fext[mesh.nodes[7].index*dof + 2] = 500. fext[mesh.nodes[5].index*dof + 2] = 1000. fext[mesh.nodes[6].index*dof + 2] = 1000. i, j = np.indices(k0run.shape) # boundary conditions for nid in [1, 10, 11, 12]: for j in [0, 1, 2, 3]: k0run[mesh.nodes[nid].index*dof+j, :] = 0 k0run[:, mesh.nodes[nid].index*dof+j] = 0 k0run = coo_matrix(k0run) u = solve(k0run, fext, silent=True) ans = np.loadtxt(os.path.join(THISDIR, 'nastran_plate_16_nodes.result.txt'), dtype=float) xyz = np.array([n.xyz for n in mesh.nodes.values()]) ind = np.lexsort((xyz[:, 1], xyz[:, 0])) xyz = xyz[ind] nodes = np.array(list(mesh.nodes.values()))[ind] pick = [n.index for n in nodes] assert np.allclose(u[2::5][pick].reshape(4, 4).T, ans, rtol=0.05)
from scipy.sparse import coo_matrix from composites.laminate import read_stack from structsolve import solve, lb from meshless.espim.read_mesh import read_mesh from meshless.espim.plate2d_calc_k0 import calc_k0 from meshless.espim.plate2d_calc_kG import calc_kG from meshless.espim.plate2d_add_k0s import add_k0s THISDIR = os.path.dirname(inspect.getfile(inspect.currentframe())) E11 = 71.e9 nu = 0.33 plyt = 0.007 laminaprop = (E11, E11, nu) lam = read_stack([0], plyt=plyt, laminaprop=laminaprop, calc_scf=True) prop_from_nodes = False k0s_method = 'cell-based' mesh = read_mesh(os.path.join(THISDIR, 'nastran_test.dat')) nodes = mesh.nodes.values() for tria in mesh.elements.values(): tria.prop = lam for node in nodes: node.prop = lam k0 = calc_k0(mesh, prop_from_nodes) add_k0s(k0, mesh, prop_from_nodes, k0s_method) dof = 5 N = k0.shape[0] // 5
def test_static_pressure(plot=False): # number of nodes nx = 29 ny = 29 # geometry a = 3 b = 7 # material properties E = 200e9 nu = 0.3 h = 0.005 lam = read_stack(stack=[0], plyt=h, laminaprop=[E, E, nu]) xtmp = np.linspace(0, a, nx) ytmp = np.linspace(0, b, ny) xmesh, ymesh = np.meshgrid(xtmp, ytmp) # getting nodes ncoords = np.vstack((xmesh.T.flatten(), ymesh.T.flatten())).T x = ncoords[:, 0] y = ncoords[:, 1] nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) nids_mesh = nids.reshape(nx, ny) n1s = nids_mesh[:-1, :-1].flatten() n2s = nids_mesh[1:, :-1].flatten() n3s = nids_mesh[1:, 1:].flatten() n4s = nids_mesh[:-1, 1:].flatten() K = np.zeros((DOF * nx * ny, DOF * nx * ny)) cyls = [] for n1, n2, n3, n4 in zip(n1s, n2s, n3s, n4s): cyl = BFSCylinder() cyl.n1 = n1 cyl.n2 = n2 cyl.n3 = n3 cyl.n4 = n4 cyl.R = 1e100 cyl.ABD = lam.ABD update_K(cyl, nid_pos, ncoords, K) cyls.append(cyl) # applying boundary conditions bk = np.zeros(K.shape[0], dtype=bool) # simply supported check = isclose(x, 0) | isclose(x, a) | isclose(y, 0) | isclose(y, b) bk[2::DOF] = check # eliminating all u,v displacements bk[0::DOF] = True bk[1::DOF] = True bu = ~bk # same as np.logical_not, defining unknown DOFs # external force vector for point load at center f = np.zeros(K.shape[0]) fmid = 1. # force at center node check = np.isclose(x, a / 2) & np.isclose(y, b / 2) f[2::DOF][check] = fmid assert f.sum() == fmid # sub-matrices corresponding to unknown DOFs Kuu = K[bu, :][:, bu] fu = f[bu] # solving Kuu = csc_matrix(Kuu) # making Kuu a sparse matrix uu = spsolve(Kuu, fu) u = np.zeros(K.shape[0], dtype=float) u[bu] = uu w = u[2::DOF].reshape(nx, ny).T print('wmax', w.max()) print('wmin', w.min()) if plot: import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.gca().set_aspect('equal') levels = np.linspace(w.min(), w.max(), 300) plt.contourf(xmesh, ymesh, w, levels=levels) plt.colorbar() plt.show()
def test_nat_freq(plot_mode=None): # number of nodes nx = 7 # along x ny = 7 # along y # geometry a = 0.6 b = 0.2 # material properties (Aluminum) E = 70e9 nu = 0.3 rho = 7.8e3 h = 0.001 lam = read_stack(stack=[0], plyt=h, laminaprop=[E, nu], rho=rho) # creating mesh x = np.linspace(0, a, nx) y = np.linspace(0, b, ny) xmesh, ymesh = np.meshgrid(x, y) # node coordinates and position in the global matrix ncoords = np.vstack((xmesh.T.flatten(), ymesh.T.flatten())).T nids = 1 + np.arange(ncoords.shape[0]) nid_pos = dict(zip(nids, np.arange(len(nids)))) nids_mesh = nids.reshape(nx, ny) n1s = nids_mesh[:-1, :-1].flatten() n2s = nids_mesh[1:, :-1].flatten() n3s = nids_mesh[1:, 1:].flatten() n4s = nids_mesh[:-1, 1:].flatten() K = np.zeros((DOF * nx * ny, DOF * nx * ny)) M = np.zeros((DOF * nx * ny, DOF * nx * ny)) cyls = [] for n1, n2, n3, n4 in zip(n1s, n2s, n3s, n4s): cyl = BFSCylinder() cyl.n1 = n1 cyl.n2 = n2 cyl.n3 = n3 cyl.n4 = n4 cyl.ABD = lam.ABD cyl.h = h cyl.R = 1e100 cyl.rho = lam.rho update_K(cyl, nid_pos, ncoords, K) update_M(cyl, nid_pos, M) cyls.append(cyl) # applying boundary conditions # simply supported # locating nodes bk = np.zeros( K.shape[0], dtype=bool) # constrained DOFs, can be used to prescribe displacements x = ncoords[:, 0] y = ncoords[:, 1] # constraining w at all edges check = (np.isclose(x, 0.) | np.isclose(x, a) | np.isclose(y, 0.) | np.isclose(y, b)) bk[2::DOF] = check # constraining u at x = 0 check = np.isclose(x, 0.) bk[0::DOF] = check # constraining v at y = 0 check = np.isclose(y, 0.) bk[1::DOF] = check # unconstrained nodes bu = ~bk # logical_not Kuu = K[bu, :][:, bu] Muu = M[bu, :][:, bu] # solving generalized eigenvalue problem num_eigenvalues = 5 print('eig solver begin') eigvals, eigvecsu = eigh(a=Kuu, b=Muu) print('eig solver end') eigvecs = np.zeros((K.shape[0], num_eigenvalues), dtype=float) eigvecs[bu, :] = eigvecsu[:, :num_eigenvalues] omegan = eigvals**0.5 # theoretical reference m = 1 n = 1 rho = lam.rho D = 2 * h**3 * E / (3 * (1 - nu**2)) wmn = (m**2 / a**2 + n**2 / b**2) * np.sqrt(D * np.pi**4 / (2 * rho * h)) / 2 print('Theoretical omega123', wmn) print(omegan[:num_eigenvalues]) assert np.isclose(omegan[0], wmn, rtol=0.01) if plot_mode is not None: import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt plt.gca().set_aspect('equal') wplot = eigvecs[2::DOF, plot_mode].reshape(nx, ny).T levels = np.linspace(wplot.min(), wplot.max(), 300) plt.contourf(xmesh, ymesh, wplot, levels=levels) plt.colorbar() plt.show()
nodes_xyz = np.array([n.pos for n in nodes]) index_ref_point = nodes_xyz.min(axis=0) index_dist = ((nodes_xyz - index_ref_point)**2).sum(axis=-1) indices = np.argsort(index_dist) for i, node in enumerate(nodes): node.index = indices[i] n = nodes.shape[0] dof = 2 # material properties E11 = 71.e9 nu = 0.33 plyt = 0.0001 lam = read_stack([0], plyt=plyt, laminaprop=(E11, E11, nu)) prop = Property(lam.A, lam.B, lam.D, lam.E) for tria in trias: tria.prop = prop #TODO allocate less memory here... k0 = np.zeros((n*dof, n*dof), dtype=np.float64) prop_from_node = False count = 0 Atotal = 0 for edge in edges: Ac = edge.Ac Atotal += Ac ipts = edge.ipts for ipt in ipts:
def test_plate_from_zero(): # Plate geometry and laminate data a = 0.406 b = 0.254 E1 = 1.295e11 E2 = 9.37e9 nu12 = 0.38 G12 = 5.24e9 G13 = 5.24e9 G23 = 5.24e9 plyt = 1.9e-4 laminaprop = (E1, E2, nu12, G12, G13, G23) angles = [0, 45, -45, 90, 90, -45, 45, 0] # Generating Mesh # --- import numpy as np from scipy.spatial import Delaunay xs = np.linspace(0, a, 8) ys = np.linspace(0, b, 8) points = np.array(np.meshgrid(xs, ys)).T.reshape(-1, 2) tri = Delaunay(points) # Using Meshless Package # --- from scipy.sparse import coo_matrix from composites.laminate import read_stack from structsolve import solve, lb from meshless.espim.read_mesh import read_delaunay from meshless.espim.plate2d_calc_k0 import calc_k0 from meshless.espim.plate2d_calc_kG import calc_kG from meshless.espim.plate2d_add_k0s import add_k0s mesh = read_delaunay(points, tri) nodes = np.array(list(mesh.nodes.values())) prop_from_nodes = True nodes_xyz = np.array([n.xyz for n in nodes]) # **Applying properties # applying heterogeneous properties for node in nodes: lam = read_stack(angles, plyt=plyt, laminaprop=laminaprop) node.prop = lam # **Defining Boundary Conditions** # DOF = 5 def bc(K, mesh): for node in nodes[nodes_xyz[:, 0] == xs.min()]: for dof in [1, 3]: j = dof - 1 K[node.index * DOF + j, :] = 0 K[:, node.index * DOF + j] = 0 for node in nodes[(nodes_xyz[:, 1] == ys.min()) | (nodes_xyz[:, 1] == ys.max())]: for dof in [2, 3]: j = dof - 1 K[node.index * DOF + j, :] = 0 K[:, node.index * DOF + j] = 0 for node in nodes[nodes_xyz[:, 0] == xs.max()]: for dof in [3]: j = dof - 1 K[node.index * DOF + j, :] = 0 K[:, node.index * DOF + j] = 0 # **Calculating Constitutive Stiffness Matrix** k0s_method = 'cell-based' k0 = calc_k0(mesh, prop_from_nodes) add_k0s(k0, mesh, prop_from_nodes, k0s_method, alpha=0.2) bc(k0, mesh) k0 = coo_matrix(k0) # **Defining Load and External Force Vector** def define_loads(mesh): loads = [] load_nodes = nodes[(nodes_xyz[:, 0] == xs.max()) & (nodes_xyz[:, 1] != ys.min()) & (nodes_xyz[:, 1] != ys.max())] fx = -1. / (nodes[nodes_xyz[:, 0] == xs.max()].shape[0] - 1) for node in load_nodes: loads.append([node, (fx, 0, 0)]) load_nodes = nodes[(nodes_xyz[:, 0] == xs.max()) & ( (nodes_xyz[:, 1] == ys.min()) | (nodes_xyz[:, 1] == ys.max()))] fx = -1. / (nodes[nodes_xyz[:, 0] == xs.max()].shape[0] - 1) / 2 for node in load_nodes: loads.append([node, (fx, 0, 0)]) return loads n = k0.shape[0] // DOF fext = np.zeros(n * DOF, dtype=np.float64) loads = define_loads(mesh) for node, force_xyz in loads: fext[node.index * DOF + 0] = force_xyz[0] print('Checking sum of forces: %s' % str(fext.reshape(-1, DOF).sum(axis=0))) # **Running Static Analysis** d = solve(k0, fext, silent=True) total_trans = (d[0::DOF]**2 + d[1::DOF]**2)**0.5 print('Max total translation', total_trans.max()) # **Calculating Geometric Stiffness Matrix** kG = calc_kG(d, mesh, prop_from_nodes) bc(kG, mesh) kG = coo_matrix(kG) # **Running Linear Buckling Analysis** eigvals, eigvecs = lb(k0, kG, silent=True) print('First 5 eigenvalues') print('\n'.join(map(str, eigvals[:5]))) assert np.allclose(eigvals[:5], [ 1004.29332981, 1822.11577078, 2898.3728806, 2947.17499169, 3297.54959342, ])