def vector_analysis(mesh, element_type, post_process=False, vtk_filename=None): # MESH # mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map logger.debug("mesh info: %d elements, %d nodes", num_elements, num_nodes) # DATA load_condition = "plane strain" # "plane stress" or "plane strain" thickness = 1 # MATERIAL matrix = base.Material("matrix", 4, 0.38, load_condition) # BSL914C epoxy fiber = base.Material("fiber", 15, 0.07, load_condition) # T300 carbon fiber # BOUNDARY CONDITIONS INSTANCES left_side = bc.DirichletBC("left side", mesh, [0], 0.0) bl_corner = bc.DirichletBC("bottom left corner", mesh, [1], 0.0) right_side = bc.DirichletBC("right side", mesh, [0], 1.0) # ASSEMBLY E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, matrix, fiber) R = np.zeros(num_nodes * 2) K = vector.assembly(num_elements, num_nodes, elements, nodal_coord, E_array, thickness) # save constrained dof rows of K # dirichlet dof are built only for boundaries with related reactions dirichlet_dof, dirichlet_values = bc.build_dirichlet_data( left_side, bl_corner) K = K.tocsr() K_rows = K[dirichlet_dof, :] K = K.tocsc() # BOUNDARY CONDITIONS APPLICATION K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, bl_corner, right_side) # SOLVER D = linalg.spsolve(K, R) reactions = K_rows.dot(D) modulus = base.compute_modulus(nodal_coord, right_side, reactions, thickness) logger.debug("E2 = %f", modulus) if post_process: D_ready = np.column_stack((D[::2], D[1::2], np.zeros(num_nodes))) D_dict = {"displacement": D_ready} mesh.point_data = D_dict mesh.write(f"../data/vtk/sample/{vtk_filename}.vtk") logger.debug("VTK file created") return modulus
def sp_base_analysis(mesh, element_type): # MESH # mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map logger.debug("mesh info: %d elements, %d nodes", num_elements, num_nodes) # DATA integration_points = 1 # hard-coded but could be removed load_condition = "plane strain" # TODO also this could be removed 'cause we need only plane strain case thickness = 1 # TODO make this a passed argument? # MATERIAL matrix = base.Material("matrix", 10, 0.3, load_condition) fiber = base.Material("fiber", 100, 0.3, load_condition) # BOUNDARY CONDITIONS INSTANCES left_side = bc.DirichletBC("left side", mesh, [0], 0.0) bl_corner = bc.DirichletBC("bottom left corner", mesh, [1], 0.0) right_side = bc.DirichletBC("right side", mesh, [0], 1.0) # ASSEMBLY E_material = base.compute_E_material(num_elements, material_map, mesh.field_data, matrix, fiber) K = sparse.csc_matrix((2 * num_nodes, 2 * num_nodes)) R = np.zeros(num_nodes * 2) K = base.sp_assembly(K, num_elements, num_nodes, elements, nodal_coord, material_map, E_material, thickness, element_type) # save constrained dof rows of K # dirichlet dof are built only for boundaries with related reactions dirichlet_dof, dirichlet_values = bc.build_dirichlet_data( left_side, bl_corner) K = K.tocsr() K_rows = K[dirichlet_dof, :] K = K.tocsc() # BOUNDARY CONDITIONS APPLICATION K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, bl_corner, right_side) # SOLVER D = linalg.spsolve(K, R) reactions = K_rows.dot(D) modulus = base.compute_modulus(nodal_coord, right_side, reactions, thickness) logger.debug("E2 = %f", modulus) return modulus
def test_compute_E_array(): element_type = "triangle" mesh_path = "tests/data/msh/test_mat.msh" load_condition = "plane stress" # "plane stress" or "plane strain" steel = base.Material("steel", 3e7, 0.25, load_condition) aluminum = base.Material("aluminum", 1e7, 0.35, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, steel, aluminum) E_array_true = np.array([ (32000000., 8000000., 0., 32000000., 0., 12000000.), (11396011.3960114, 3988603.98860399, 0., 11396011.3960114, 0., 3703703.7037037), ]) np.testing.assert_allclose(E_array_true, E_array)
def test_compute_K_entry(): mesh_path = "tests/data/msh/test.msh" element_type = "triangle" integration_points = 1 load_condition = "plane stress" # "plane stress" or "plane strain" thickness = 0.5 steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, steel) X = lambda c, e, i, j: c[e[:, i]][:, 0] - c[e[:, j]][:, 0] Y = lambda c, e, i, j: c[e[:, i]][:, 1] - c[e[:, j]][:, 1] c = nodal_coord e = elements J = X(c, e, 1, 0) * Y(c, e, 2, 0) - X(c, e, 2, 0) * Y(c, e, 1, 0) b = np.array([ [Y(c, e, 1, 2), Y(c, e, 2, 0), Y(c, e, 0, 1)], [X(c, e, 2, 1), X(c, e, 0, 2), X(c, e, 1, 0)], ]) row_0, col_0 = np.unravel_index(0, (6, 6)) k_0 = vector.compute_K_entry(row_0, col_0, nodal_coord, elements, b, J, E_array, thickness) row_35, col_35 = np.unravel_index(35, (6, 6)) k_35 = vector.compute_K_entry(row_35, col_35, nodal_coord, elements, b, J, E_array, thickness) k_0_true = np.array([5333333.33333333, 4500000.]) k_35_true = np.array([12000000., 14000000.]) np.testing.assert_allclose(k_0_true, k_0) np.testing.assert_allclose(k_35_true, k_35)
def test_stiffness_matrix(): mesh_path = "tests/data/msh/test.msh" element_type = "triangle" load_condition = "plane stress" # "plane stress" or "plane strain" thickness = 0.5 steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map E_material = base.compute_E_material(num_elements, material_map, mesh.field_data, steel) k_0 = base.stiffness_matrix(0, elements, nodal_coord, material_map, E_material, thickness, element_type) k_1 = base.stiffness_matrix(1, elements, nodal_coord, material_map, E_material, thickness, element_type) k_0_true = np.array([ (5333333.33333333, 0.0, -5333333.33333333, 2000000., 0., -2000000.), (0., 2000000., 3000000., -2000000., -3000000., 0.), (-5333333.33333333, 3000000., 9833333.33333333, -5000000., -4500000., 2000000.), (2000000., -2000000., -5000000., 14000000., 3000000., -12000000.), (0., -3000000., -4500000., 3000000., 4500000., 0.), (-2000000., 0., 2000000., -12000000., 0., 12000000.), ]) k_1_true = np.array([ (4500000., 0., 0., -3000000., -4500000., 3000000.), (0., 12000000., -2000000., 0., 2000000., -12000000.), (0., -2000000., 5333333.33333333, 0., -5333333.33333333, 2000000.), (-3000000., 0., 0., 2000000., 3000000., -2000000.), (-4500000., 2000000., -5333333.33333333, 3000000., 9833333.33333333, -5000000.), (3000000., -12000000., 2000000., -2000000., -5000000., 14000000.), ]) np.testing.assert_allclose(k_0_true, k_0) np.testing.assert_allclose(k_1_true, k_1)
def test_compute_E_material(): element_type = "triangle" mesh_path = "tests/data/msh/test.msh" load_condition = "plane stress" # "plane stress" or "plane strain" steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) num_elements = mesh.cells_dict[element_type].shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map E_material = base.compute_E_material(num_elements, material_map, mesh.field_data, steel) E_steel = np.array([ (3.2e7, 8e6, 0.0), (8e6, 3.2e7, 0.0), (0.0, 0.0, 1.2e7), ]) # TODO add aluminum matrix testing np.testing.assert_allclose(E_steel, E_material[0])
def test_sparse_fem(): mesh_path = "tests/data/msh/test.msh" element_type = "triangle" load_condition = "plane stress" # "plane stress" or "plane strain" thickness = 0.5 steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map left_side = bc.DirichletBC("left side", mesh, [0, 1], 0.0) br_corner = bc.DirichletBC("bottom right corner", mesh, [1], 0.0) tr_corner = bc.NeumannBC("top right corner", mesh, [1], -1000.0) E_material = base.compute_E_material(num_elements, material_map, mesh.field_data, steel) K = sparse.csc_matrix((2 * num_nodes, 2 * num_nodes)) R = np.zeros(num_nodes * 2) # for e in range(num_elements): # K = base.sparse_assembly(K, e, mesh, E_material, thickness, element_type, integration_points) K = base.sp_assembly(K, num_elements, num_nodes, elements, nodal_coord, material_map, E_material, thickness, element_type) print(K) K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, br_corner) R = bc.apply_neumann(R, tr_corner) D = linalg.spsolve(K, R) D_true = np.array([ 0.0, 0.0, 1.90773874e-05, 0.0, 8.73032981e-06, -7.41539125e-05, 0.0, 0.0 ]) np.testing.assert_almost_equal(D_true, D)
def test_fem(): mesh_path = "tests/data/msh/test.msh" element_type = "triangle" integration_points = 1 load_condition = "plane stress" # "plane stress" or "plane strain" thickness = 0.5 steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map left_side = bc.DirichletBC("left side", mesh, [0, 1], 0.0) br_corner = bc.DirichletBC("bottom right corner", mesh, [1], 0.0) tr_corner = bc.NeumannBC("top right corner", mesh, [1], -1000.0) E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, steel) R = np.zeros(num_nodes * 2) K = vector.assembly(num_elements, num_nodes, elements, nodal_coord, E_array, thickness) K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, br_corner) R = bc.apply_neumann(R, tr_corner) D = linalg.spsolve(K, R) D_true = np.array([ 0.0, 0.0, 1.90773874e-05, 0.0, 8.73032981e-06, -7.41539125e-05, 0.0, 0.0 ]) # np.testing.assert_allclose(D_true, D) # FIXME some zeros are 1.0e-20 why?? np.testing.assert_almost_equal(D_true, D)
def test_vect_assembly(): mesh_path = "tests/data/msh/test.msh" element_type = "triangle" load_condition = "plane stress" # "plane stress" or "plane strain" thickness = 0.5 steel = base.Material("steel", 3e7, 0.25, load_condition) mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map left_side = bc.DirichletBC("left side", mesh, [0, 1], 0.0) br_corner = bc.DirichletBC("bottom right corner", mesh, [1], 0.0) tr_corner = bc.NeumannBC("top right corner", mesh, [1], -1000.0) E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, steel) R = np.zeros(num_nodes * 2) K = vector.assembly(num_elements, num_nodes, elements, nodal_coord, E_array, thickness) K_true = np.array([ [ 9833333.33333333, 0., -5333333.33333333, 2000000., 0., -5000000., -4500000., 3000000. ], [ 0., 14000000., 3000000., -2000000., -5000000., 0., 2000000., -12000000. ], [ -5333333.33333333, 3000000., 9833333.33333333, -5000000., -4500000., 2000000., 0., 0. ], [ 2000000., -2000000., -5000000., 14000000., 3000000., -12000000., 0., 0. ], [ 0., -5000000., -4500000., 3000000., 9833333.33333333, 0., -5333333.33333333, 2000000. ], [ -5000000., 0., 2000000., -12000000., 0., 14000000., 3000000., -2000000. ], [ -4500000., 2000000., 0., 0., -5333333.33333333, 3000000., 9833333.33333333, -5000000. ], [ 3000000., -12000000., 0., 0., 2000000., -2000000., -5000000., 14000000. ], ]) np.testing.assert_allclose(K_true, K.toarray()) K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, br_corner) R = bc.apply_neumann(R, tr_corner) K_true_bc = np.array([ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [ -5.33333333e+06, 3.00000000e+06, 9.83333333e+06, -5.00000000e+06, -4.50000000e+06, 2.00000000e+06, 0.0, 0.0 ], [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [ 0.0, -5.00000000e+06, -4.50000000e+06, 3.00000000e+06, 9.83333333e+06, 0.0, -5.33333333e+06, 2.00000000e+06 ], [ -5.00000000e+06, 0.0, 2.00000000e+06, -1.20000000e+07, 0.0, 1.40000000e+07, 3.00000000e+06, -2.00000000e+06 ], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], ]) np.testing.assert_allclose(K_true_bc, K.toarray())
def test_feap_1(): # LOGGING main_log = logging.getLogger(__name__) main_log.setLevel(logging.INFO) main_handler = logging.StreamHandler() # main_log handler main_handler.setLevel(logging.INFO) main_formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) # main_log formatter main_handler.setFormatter(main_formatter) main_log.addHandler(main_handler) feat_log = logging.getLogger("feat") feat_log.setLevel(logging.DEBUG) feat_handler = logging.StreamHandler() feat_handler.setLevel(logging.DEBUG) feat_formatter = logging.Formatter( '%(name)s - %(levelname)s - %(message)s') feat_handler.setFormatter(feat_formatter) feat_log.addHandler(feat_handler) # SETTINGS mesh_path = "tests/data/msh/feap_1.msh" main_log.info("MESH FILE: %s", mesh_path) # DATA element_type = "triangle" load_condition = "plane strain" # "plane stress" or "plane strain" thickness = 1 main_log.info("LOAD CONDITION: %s", load_condition) main_log.info("THICKNESS: %s", thickness) # MATERIAL cheese = base.Material("cheese", 70, 0.3, load_condition) main_log.info("MATERIALS: TODO") # MESH mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map main_log.info("MESH INFO: %d elements, %d nodes", num_elements, num_nodes) # BOUNDARY CONDITIONS INSTANCES left_side = bc.DirichletBC("left side", mesh, [0], 0.0) bl_corner = bc.DirichletBC("bottom left corner", mesh, [1], 0.0) right_side = bc.DirichletBC("right side", mesh, [0], 1.0) main_log.info("BOUNDARY CONDITIONS: TODO") # ASSEMBLY E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, cheese) R = np.zeros(num_nodes * 2) K = vector.assembly(num_elements, num_nodes, elements, nodal_coord, E_array, thickness) main_log.debug("STIFFNESS MATRIX (K) BEFORE BC:\n %s\n", K) # save constrained dof rows of K # dirichlet dof are built only for boundaries with related reactions dirichlet_dof, dirichlet_values = bc.build_dirichlet_data( left_side, bl_corner) K = K.tocsr() K_rows = K[dirichlet_dof, :] K = K.tocsc() # BOUNDARY CONDITIONS APPLICATION K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, bl_corner, right_side) main_log.debug("STIFFNESS MATRIX (K) AFTER BC:\n %s\n", K) main_log.debug("LOAD VECTOR (R) BEFORE BC:\n %s\n", R) # SOLVER D = linalg.spsolve(K, R) main_log.info("DISPLACEMENTS VECTOR (D):\n %s\n", D) reactions = K_rows.dot(D) main_log.debug("REACTIONS (dirichlet dofs):\n %s\n", reactions) modulus = base.compute_modulus(nodal_coord, right_side, reactions, thickness) main_log.info("RESULTING ELASTIC MODULUS: %f", modulus) comparable_dofs = [2, 4, 5, 7] D_true = np.array([ 0.0, 0.0, 1.0, np.NaN, 1.0, -4.28571429e-01, 0.0, -4.28571429e-01, ]) np.testing.assert_allclose(D_true[comparable_dofs], D[comparable_dofs])
def test_feap_2(poisson, D_true, reactions_true): # LOGGING main_log = logging.getLogger(__name__) main_log.setLevel(logging.DEBUG) main_handler = logging.StreamHandler() # main_log handler main_handler.setLevel(logging.DEBUG) main_formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) # main_log formatter main_handler.setFormatter(main_formatter) main_log.addHandler(main_handler) feat_log = logging.getLogger("feat") feat_log.setLevel(logging.DEBUG) feat_handler = logging.StreamHandler() feat_handler.setLevel(logging.DEBUG) feat_formatter = logging.Formatter( '%(name)s - %(levelname)s - %(message)s') feat_handler.setFormatter(feat_formatter) feat_log.addHandler(feat_handler) # SETTINGS mesh_path = "tests/data/msh/feap_2.msh" main_log.info("MESH FILE: %s", mesh_path) # DATA element_type = "triangle" load_condition = "plane strain" # "plane stress" or "plane strain" thickness = 1 main_log.info("LOAD CONDITION: %s", load_condition) main_log.info("THICKNESS: %s", thickness) # MATERIAL rubber = base.Material("rubber", 10, poisson, load_condition) main_log.info("MATERIALS: TODO") # MESH mesh = meshio.read(mesh_path) elements = mesh.cells_dict[element_type] nodal_coord = mesh.points[:, :2] num_elements = elements.shape[0] num_nodes = nodal_coord.shape[0] material_map = mesh.cell_data_dict["gmsh:physical"][ element_type] - 1 # element-material map main_log.info("MESH INFO: %d elements, %d nodes", num_elements, num_nodes) # BOUNDARY CONDITIONS INSTANCES left_side = bc.DirichletBC("left side", mesh, [0], 0.0) b_corner = bc.DirichletBC("bottom corner", mesh, [1], 0.0) r_corner_x = bc.NeumannBC("right corner", mesh, [0], 0.4) r_corner_y = bc.NeumannBC("right corner", mesh, [1], 0.4) main_log.info("BOUNDARY CONDITIONS: TODO") # ASSEMBLY E_array = vector.compute_E_array(num_elements, material_map, mesh.field_data, rubber) main_log.debug("E array:\n %s\n", E_array) R = np.zeros(num_nodes * 2) K = vector.assembly(num_elements, num_nodes, elements, nodal_coord, E_array, thickness) main_log.debug("STIFFNESS MATRIX (K) BEFORE BC:\n %s\n", K.todense()) # save constrained dof rows of K # dirichlet dof are built only for boundaries with related reactions dirichlet_dof, dirichlet_values = bc.build_dirichlet_data( left_side, b_corner) K = K.tocsr() K_rows = K[dirichlet_dof, :] K = K.tocsc() # BOUNDARY CONDITIONS APPLICATION K, R = bc.sp_apply_dirichlet(num_nodes, K, R, left_side, b_corner) R = bc.apply_neumann(R, r_corner_x, r_corner_y) main_log.debug("STIFFNESS MATRIX (K) AFTER BC:\n %s\n", K.todense()) main_log.debug("LOAD VECTOR (R) BEFORE BC:\n %s\n", R) # SOLVER D = linalg.spsolve(K, R) main_log.info("DISPLACEMENTS VECTOR (D):\n %s\n", D) reactions = K_rows.dot(D) main_log.debug("REACTIONS (dirichlet dofs):\n %s\n", reactions) np.testing.assert_allclose(D_true, D) np.testing.assert_allclose(reactions_true, reactions)