Ejemplo n.º 1
0
Archivo: fem.py Proyecto: basic-ph/feat
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
Ejemplo n.º 2
0
Archivo: fem.py Proyecto: basic-ph/feat
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
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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])
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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())
Ejemplo n.º 10
0
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])
Ejemplo n.º 11
0
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)