Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
"""
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))
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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
Exemplo n.º 12
0
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