def test_eigs_beam(): """Eigenvalues of a cantilever beam""" nnodes = 10 x = np.linspace(0, np.pi, nnodes) nodes = np.zeros((nnodes, 3)) nodes[:, 0] = range(nnodes) nodes[:, 1] = x cons = np.zeros((nnodes, 3)) cons[0, :] = -1 cons[:, 0] = -1 mats = np.array([[1.0, 1.0, 1.0, 1.0]]) elements = np.zeros((nnodes - 1, 5), dtype=int) elements[:, 0] = range(nnodes - 1) elements[:, 1] = 7 elements[:, 3] = range(nnodes - 1) elements[:, 4] = range(1, nnodes) assem_op, bc_array, neq = ass.DME(cons, elements, ndof_node=3) stiff, mass = ass.assembler(elements, mats, nodes, neq, assem_op) vals, _ = eigsh(stiff, M=mass, which="SM") vals_analytic = np.array([ 0.596864162694467, 1.49417561427335, 2.50024694616670, 3.49998931984744, 4.50000046151508, 5.49999998005609 ]) assert np.allclose(vals**0.25, vals_analytic, rtol=1e-2)
def solids_GUI(compute_strains=False, plot_contours=True): """ Run a complete workflow for a Finite Element Analysis Parameters ---------- compute_strains : Bool (optional) Boolean variable to compute Strains and Stresses at nodes. By default it is False. plot_contours : Bool (optional) Boolean variable to plot contours of the computed variables. By default it is True. Returns ------- UC : ndarray (nnodes, 2) Displacements at nodes. E_nodes : ndarray (nnodes, 3), optional Strains at nodes. It is returned when `compute_strains` is True. S_nodes : ndarray (nnodes, 3), optional Stresses at nodes. It is returned when `compute_strains` is True. """ folder = pre.initial_params() start_time = datetime.now() echo = False #%% PRE-PROCESSING nodes, mats, elements, loads = pre.readin(folder=folder) if echo: pre.echomod(nodes, mats, elements, loads, folder=folder) DME , IBC , neq = ass.DME(nodes, elements) print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) #%% SYSTEM ASSEMBLY KG = ass.assembler(elements, mats, nodes, neq, DME) RHSG = ass.loadasem(loads, IBC, neq) #%% SYSTEM SOLUTION UG = sol.static_sol(KG, RHSG) if not(np.allclose(KG.dot(UG)/KG.max(), RHSG/KG.max())): print("The system is not in equilibrium!") end_time = datetime.now() print('Duration for system solution: {}'.format(end_time - start_time)) #%% POST-PROCESSING start_time = datetime.now() UC = pos.complete_disp(IBC, nodes, UG) E_nodes, S_nodes = None, None if compute_strains: E_nodes, S_nodes = pos.strain_nodes(nodes , elements, mats, UC) if plot_contours: pos.fields_plot(elements, nodes, UC, E_nodes=E_nodes, S_nodes=S_nodes) end_time = datetime.now() print('Duration for post processing: {}'.format(end_time - start_time)) print('Analysis terminated successfully!') return UC, E_nodes, S_nodes if compute_strains else UC
def test_2_elements(): """2x1 mesh cantilever beam""" nodes = np.array([[0, 0, 0], [1, 1, 0], [2, 2, 0], [3, 0, 1], [4, 1, 1], [5, 2, 1]]) cons = np.array([[-1, -1], [0, 0], [0, 0], [-1, -1], [0, 0], [0, 0]]) eles = np.array([[0, 1, 0, 0, 1, 4, 3], [1, 1, 0, 1, 2, 5, 4]]) loads = np.array([[2, 0, -0.5], [5, 0, -0.5]]) mater = np.array([[1.0, 0.3]]) assem_op, bc_array, neq = ass.DME(cons, eles) stiff, _ = ass.assembler(eles, mater, nodes, neq, assem_op) load_vec = ass.loadasem(loads, bc_array, neq) disp = sol.static_sol(stiff, load_vec) disp_complete = pos.complete_disp(bc_array, nodes, disp) disp_analytic = 1 / 45 * np.array([[0, 0], [-273, -390], [-364, -1144], [0, 0], [273, -390], [364, -1144]]) assert np.allclose(disp_complete, disp_analytic)
def test_4_elements(): """2×2 mesh with uniaxial load""" nodes = np.array([[0, 0, 0], [1, 2, 0], [2, 2, 2], [3, 0, 2], [4, 1, 0], [5, 2, 1], [6, 1, 2], [7, 0, 1], [8, 1, 1]]) cons = np.array([[0, -1], [0, -1], [0, 0], [0, 0], [-1, -1], [0, 0], [0, 0], [0, 0], [0, 0]]) eles = np.array([[0, 1, 0, 0, 4, 8, 7], [1, 1, 0, 4, 1, 5, 8], [2, 1, 0, 7, 8, 6, 3], [3, 1, 0, 8, 5, 2, 6]]) loads = np.array([[3, 0, 1], [6, 0, 2], [2, 0, 1]]) mater = np.array([[1.0, 0.3]]) assem_op, bc_array, neq = ass.DME(cons, eles) stiff, _ = ass.assembler(eles, mater, nodes, neq, assem_op) load_vec = ass.loadasem(loads, bc_array, neq) disp = sol.static_sol(stiff, load_vec) disp_complete = pos.complete_disp(bc_array, nodes, disp) disp_analytic = np.array([[0.6, 0.0], [-0.6, 0.0], [-0.6, 4.0], [0.6, 4.0], [0.0, 0.0], [-0.6, 2.0], [0.0, 4.0], [0.6, 2.0], [0.0, 2.0]]) assert np.allclose(disp_complete, disp_analytic)
def test_beams(): """Beams with axial force""" # Analytic problem nodes = np.array([[0, 0.0, 0.0], [1, 0.0, 6.0], [2, 4.0, 6.0]]) cons = np.array([[-1, -1, -1], [0, 0, 0], [-1, -1, -1]]) mats = np.array([[200e9, 1.33e-4, 0.04]]) elements = np.array([[0, 8, 0, 0, 1], [1, 8, 0, 1, 2]]) loads = np.array([[1, -12000, -24000, -6000]]) assem_op, bc_array, neq = ass.DME(cons, elements, ndof_node=3) stiff, _ = ass.assembler(elements, mats, nodes, neq, assem_op, sparse=False) load_vec = ass.loadasem(loads, bc_array, neq, ndof_node=3) solution = sol.static_sol(stiff, load_vec) solution_analytic = np.array([-6.29e-6, -1.695e-5, -0.13e-3]) assert np.allclose(solution, solution_analytic, rtol=1e-1)
def test_eigs_truss(): """Eigenvalues of a bar""" nnodes = 513 x = np.linspace(0, np.pi, nnodes) nodes = np.zeros((nnodes, 3)) nodes[:, 0] = range(nnodes) nodes[:, 1] = x cons = np.zeros((nnodes, 2)) cons[:, 1] = -1 cons[0, 0] = -1 cons[-1, 0] = -1 mats = np.array([[1.0, 1.0, 1.0]]) elements = np.zeros((nnodes - 1, 5), dtype=int) elements[:, 0] = range(nnodes - 1) elements[:, 1] = 6 elements[:, 3] = range(nnodes - 1) elements[:, 4] = range(1, nnodes) assem_op, bc_array, neq = ass.DME(cons, elements) stiff, mass = ass.assembler(elements, mats, nodes, neq, assem_op) vals, _ = eigsh(stiff, M=mass, which="SM") assert np.allclose(vals, np.linspace(1, 6, 6)**2, rtol=1e-2)
""" from __future__ import division, print_function import numpy as np from datetime import datetime import solidspy.preprocesor as pre import solidspy.postprocesor as pos import solidspy.assemutil as ass import solidspy.solutil as sol start_time = datetime.now() #%% PRE-PROCESSING nodes, mats, elements, loads = pre.readin() DME , IBC , neq = ass.DME(nodes, elements) print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) #%% SYSTEM ASSEMBLY KG = ass.assembler(elements, mats, nodes, neq, DME, sparse=False) RHSG = ass.loadasem(loads, IBC, neq) ##%% SYSTEM SOLUTION UG = sol.static_sol(KG, RHSG) if not(np.allclose(KG.dot(UG)/KG.max(), RHSG/KG.max())): print("The system is not in equilibrium!") end_time = datetime.now() print('Duration for system solution: {}'.format(end_time - start_time))
def solids_GUI(plot_contours=True, compute_strains=False, folder=None): """ Run a complete workflow for a Finite Element Analysis Parameters ---------- plot_contours : Bool (optional) Boolean variable to plot contours of the computed variables. By default it is True. compute_strains : Bool (optional) Boolean variable to compute Strains and Stresses at nodes. By default it is False. folder : string (optional) String with the path to the input files. If not provided it would ask for it in a pop-up window. Returns ------- UC : ndarray (nnodes, 2) Displacements at nodes. E_nodes : ndarray (nnodes, 3), optional Strains at nodes. It is returned when `compute_strains` is True. S_nodes : ndarray (nnodes, 3), optional Stresses at nodes. It is returned when `compute_strains` is True. """ if folder is None: folder = pre.initial_params() start_time = datetime.now() echo = False # Pre-processing nodes, mats, elements, loads = pre.readin(folder=folder) if echo: pre.echomod(nodes, mats, elements, loads, folder=folder) DME, IBC, neq = ass.DME(nodes, elements) print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) # System assembly KG = ass.assembler(elements, mats, nodes, neq, DME) RHSG = ass.loadasem(loads, IBC, neq) # System solution UG = sol.static_sol(KG, RHSG) if not (np.allclose(KG.dot(UG) / KG.max(), RHSG / KG.max())): print("The system is not in equilibrium!") end_time = datetime.now() print('Duration for system solution: {}'.format(end_time - start_time)) # Post-processing start_time = datetime.now() UC = pos.complete_disp(IBC, nodes, UG) E_nodes, S_nodes = None, None if compute_strains: E_nodes, S_nodes = pos.strain_nodes(nodes, elements, mats, UC) if plot_contours: pos.fields_plot(elements, nodes, UC, E_nodes=E_nodes, S_nodes=S_nodes) end_time = datetime.now() print('Duration for post processing: {}'.format(end_time - start_time)) print('Analysis terminated successfully!') return (UC, E_nodes, S_nodes) if compute_strains else UC
def test_dense_assem(): """Tests for dense assembler""" # 2 x 2 mesh mats = np.array([[16, 1 / 3]]) nodes = np.array([[0, -1, -1], [1, 0, -1], [2, 1, -1], [3, -1, 0], [4, 0, 0], [5, 1, 0], [6, -1, 1], [7, 0, 1], [8, 1, 1]]) elements = np.array([[0, 1, 0, 0, 1, 4, 3], [1, 1, 0, 1, 2, 5, 4], [2, 1, 0, 3, 4, 7, 6], [3, 1, 0, 4, 5, 8, 7]]) DME = np.array( [[0, 1, 2, 3, 8, 9, 6, 7], [2, 3, 4, 5, 10, 11, 8, 9], [6, 7, 8, 9, 14, 15, 12, 13], [8, 9, 10, 11, 16, 17, 14, 15]], dtype=np.int) neq = 18 K_ass = ass.dense_assem(elements, mats, nodes, neq, DME) K_exact = np.array( [[8, 3, -5, 0, 0, 0, 1, 0, -4, -3, 0, 0, 0, 0, 0, 0, 0, 0], [3, 8, 0, 1, 0, 0, 0, -5, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0], [-5, 0, 16, 0, -5, 0, -4, 3, 2, 0, -4, -3, 0, 0, 0, 0, 0, 0], [0, 1, 0, 16, 0, 1, 3, -4, 0, -10, -3, -4, 0, 0, 0, 0, 0, 0], [0, 0, -5, 0, 8, -3, 0, 0, -4, 3, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, -3, 8, 0, 0, 3, -4, 0, -5, 0, 0, 0, 0, 0, 0], [1, 0, -4, 3, 0, 0, 16, 0, -10, 0, 0, 0, 1, 0, -4, -3, 0, 0], [0, -5, 3, -4, 0, 0, 0, 16, 0, 2, 0, 0, 0, -5, -3, -4, 0, 0], [-4, -3, 2, 0, -4, 3, -10, 0, 32, 0, -10, 0, -4, 3, 2, 0, -4, -3], [-3, -4, 0, -10, 3, -4, 0, 2, 0, 32, 0, 2, 3, -4, 0, -10, -3, -4], [0, 0, -4, -3, 1, 0, 0, 0, -10, 0, 16, 0, 0, 0, -4, 3, 1, 0], [0, 0, -3, -4, 0, -5, 0, 0, 0, 2, 0, 16, 0, 0, 3, -4, 0, -5], [0, 0, 0, 0, 0, 0, 1, 0, -4, 3, 0, 0, 8, -3, -5, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, -5, 3, -4, 0, 0, -3, 8, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, -4, -3, 2, 0, -4, 3, -5, 0, 16, 0, -5, 0], [0, 0, 0, 0, 0, 0, -3, -4, 0, -10, 3, -4, 0, 1, 0, 16, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, -4, -3, 1, 0, 0, 0, -5, 0, 8, 3], [0, 0, 0, 0, 0, 0, 0, 0, -3, -4, 0, -5, 0, 0, 0, 1, 3, 8]]) assert np.allclose(K_ass, K_exact) # Test for uel with all ones def uel_ones(elcoord, par1, par0): return np.ones((8, 8)), 8, 1 nodes = np.zeros((9, 5)) nodes[:, 0] = range(0, 9) nodes[:, 1:3] = np.array([[0, 0], [1, 0], [2, 0], [0, 1], [1, 1], [2, 1], [0, 2], [1, 2], [2, 2]]) elements = np.ones((4, 7), dtype=np.int) elements[:, 0] = range(0, 4) elements[:, 2] = 0 elements[:, 3:] = np.array([[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]) mats = np.array([[1, 0.3]]) DME, IBC, neq = ass.DME(nodes, elements) stiff = ass.assembler(elements, mats, nodes, neq, DME, sparse=False, uel=uel_ones) stiff_exact = np.array( [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1, 0, 0], [1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1, 0, 0], [1, 1, 2, 2, 1, 1, 2, 2, 4, 4, 2, 2, 1, 1, 2, 2, 1, 1], [1, 1, 2, 2, 1, 1, 2, 2, 4, 4, 2, 2, 1, 1, 2, 2, 1, 1], [0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1], [0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1]]) assert np.allclose(stiff, stiff_exact) # Test assembly of a truss length = 10 * np.cos(np.pi / 6) nodes = np.array([[0.0, length, 0.0, 0.0, 0.0], [1.0, 0.0, 5.0, -1.0, 0.0], [2.0, 0.0, 0.0, -1.0, -1.0]]) mats = np.array([[1e6, 0.01]]) elements = np.array([[0, 6, 0, 2, 0], [1, 6, 0, 1, 0], [2, 6, 0, 1, 2]]) DME, IBC, neq = ass.DME(nodes, elements) stiff = ass.assembler(elements, mats, nodes, neq, DME, sparse=False) stiff_exact = 250 * np.array( [[8 / np.sqrt(3) + 3, -np.sqrt(3), np.sqrt(3)], [-np.sqrt(3), 1, -1], [np.sqrt(3), -1, 9]]) assert np.allclose(stiff, stiff_exact)
np.savetxt(os.path.join(folder,"loads.txt"),loads,fmt="%.3f",delimiter="\t") np.savetxt(os.path.join(folder,"eles.txt"),elements,fmt="%i",delimiter="\t") t2=time.time() print("grid assembly ", t2-t1) start_time = dt.now() echo = False compute_strains=True plot_contours=False nodes, mats, elements, loads = pre.readin(folder=folder) if echo: pre.echomod(nodes, mats, elements, loads, folder=folder) DME, IBC, neq = ass.DME(nodes, elements) # boundary conditions asembly?? # DME #IBC list of "equations in x y direction for each node, -1 indicates no equations of movement, as completly fixed --> related to boundary conditions # neq total number of equations # DME is like list of independent equations per element(square, so just rearanged IBC for elements,side node zeros are at the end because of fixed length( for other element shape= # # # print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) # System assembly t1=time.time() KG = ass.assembler(elements, mats, nodes, neq, DME,sparse=False)
def solids_auto(data, plot_contours=True, compute_strains=False): """ Run a complete workflow for a Finite Element Analysis Parameters ---------- data : dict Simulation data composed of nodes, constrains, elements, materials and loads. plot_contours : Bool (optional) Boolean variable to plot contours of the computed variables. By default it is True. compute_strains : Bool (optional) Boolean variable to compute Strains and Stresses at nodes. By default it is False. Returns ------- UC : ndarray (nnodes, 2) Displacements at nodes. E_nodes : ndarray (nnodes, 3), optional Strains at nodes. It is returned when `compute_strains` is True. S_nodes : ndarray (nnodes, 3), optional Stresses at nodes. It is returned when `compute_strains` is True. """ # Retrieving data nodes = data["nodes"] cons = data["cons"] elements = data["elements"] mats = data["mats"] loads = data["loads"] # Pre-processing assem_op, bc_array, neq = ass.DME(cons, elements) print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) # System assembly stiff_mat, _ = ass.assembler(elements, mats, nodes, neq, assem_op) rhs_vec = ass.loadasem(loads, bc_array, neq) # System solution start_time = datetime.now() disp = sol.static_sol(stiff_mat, rhs_vec) if not np.allclose( stiff_mat.dot(disp) / stiff_mat.max(), rhs_vec / stiff_mat.max()): print("The system is not in equilibrium!") end_time = datetime.now() print('Duration for system solution: {}'.format(end_time - start_time)) # Post-processing start_time = datetime.now() disp_complete = pos.complete_disp(bc_array, nodes, disp) strain_nodes, stress_nodes = None, None if compute_strains: strain_nodes, stress_nodes = pos.strain_nodes(nodes, elements, mats, disp_complete) if plot_contours: pos.fields_plot(elements, nodes, disp_complete, E_nodes=strain_nodes, S_nodes=stress_nodes) end_time = datetime.now() print('Duration for post processing: {}'.format(end_time - start_time)) print('Analysis terminated successfully!') if compute_strains: return (disp_complete, strain_nodes, stress_nodes) else: return disp_complete
def solids_GUI(plot_contours=True, compute_strains=False, folder=None): """ Run a complete workflow for a Finite Element Analysis Parameters ---------- plot_contours : Bool (optional) Boolean variable to plot contours of the computed variables. By default it is True. compute_strains : Bool (optional) Boolean variable to compute Strains and Stresses at nodes. By default it is False. folder : string (optional) String with the path to the input files. If not provided it would ask for it in a pop-up window. Returns ------- UC : ndarray (nnodes, 2) Displacements at nodes. E_nodes : ndarray (nnodes, 3), optional Strains at nodes. It is returned when `compute_strains` is True. S_nodes : ndarray (nnodes, 3), optional Stresses at nodes. It is returned when `compute_strains` is True. """ if folder is None: folder = pre.initial_params() start_time = datetime.now() echo = False # Pre-processing nodes, mats, elements, loads = pre.readin(folder=folder) if echo: pre.echomod(nodes, mats, elements, loads, folder=folder) assem_op, bc_array, neq = ass.DME(nodes[:, -2:], elements) print("Number of nodes: {}".format(nodes.shape[0])) print("Number of elements: {}".format(elements.shape[0])) print("Number of equations: {}".format(neq)) # System assembly stiff_mat, _ = ass.assembler(elements, mats, nodes[:, :3], neq, assem_op) rhs_vec = ass.loadasem(loads, bc_array, neq) # System solution disp = sol.static_sol(stiff_mat, rhs_vec) if not np.allclose( stiff_mat.dot(disp) / stiff_mat.max(), rhs_vec / stiff_mat.max()): print("The system is not in equilibrium!") end_time = datetime.now() print('Duration for system solution: {}'.format(end_time - start_time)) # Post-processing start_time = datetime.now() disp_complete = pos.complete_disp(bc_array, nodes, disp) strain_nodes, stress_nodes = None, None if compute_strains: strain_nodes, stress_nodes = pos.strain_nodes(nodes, elements, mats, disp_complete) if plot_contours: pos.fields_plot(elements, nodes, disp_complete, E_nodes=strain_nodes, S_nodes=stress_nodes) end_time = datetime.now() print('Duration for post processing: {}'.format(end_time - start_time)) print('Analysis terminated successfully!') if compute_strains: return (disp_complete, strain_nodes, stress_nodes) else: return disp_complete