diff --git a/build-package.py b/build-package.py new file mode 100644 index 0000000..02c2df4 --- /dev/null +++ b/build-package.py @@ -0,0 +1,26 @@ + +import os, sys + +def update_setup(package_name, package_version, package_deps): + + with open("setup-template.py", "r") as f: + setup_template = f.read() + + with open("setup.py", "w") as f: + f.write(setup_template.format(package_name=package_name, package_version=package_version, package_depends=package_deps)) + +def build_package(): + os.system("python -m build --wheel") + +if __name__ == "__main__": + + package_version = "3.6.3" + + update_setup("calfem-python", package_version, "'numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'") + + build_package() + + update_setup("calfem-python-small", package_version, "'numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'") + + build_package() + diff --git a/calfem/core.py b/calfem/core.py index 6029526..a9dd3fc 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -6,7 +6,7 @@ """ from scipy.sparse.linalg import dsolve -from scipy.linalg import eig +from scipy.linalg import eig, lu import numpy as np import logging as cflog @@ -77,384 +77,409 @@ def info(msg): """Write ``msg`` to info log.""" cflog.info(" calfem.core: "+msg) - def spring1e(ep): """ + Ke = spring1e(ep) + ------------------------------------------------------------- + PURPOSE Compute element stiffness matrix for spring element. - - :param float ep: spring stiffness or analog quantity (ep = k). - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') - + + INPUT: ep = [k] spring stiffness or analog quantity + + OUTPUT: Ke : spring stiffness matrix, [2 x 2] + ------------------------------------------------------------- -def spring1s(ep, ed): - """ - Compute element force in spring element (spring1e). - - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force [N] + LAST MODIFIED: P-E Austrell 1994-11-02 + O Dahlblom 2022-11-15 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - k = ep - return k*(ed[1]-ed[0]) + k = ep + Ke = k * np.array([ + [1, -1], + [-1, 1] + ]) -def bar1e(ep): - """ - Compute element stiffness matrix for spring element. - - :param ep float: spring stiffness or analog quantity - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') + return Ke -def bar1s(ep, ed): +def spring1s(ep, ed): """ + es = spring1s(ep, ed) + ------------------------------------------------------------- + PURPOSE Compute element force in spring element (spring1e). - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force - """ - k = ep - return k*(ed[1]-ed[0]) - - -def bar2e(ex, ey, ep): - """ - Compute the element stiffness matrix for two dimensional bar element. + INPUT: ep = [k] spring stiffness or analog quantity - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: [E, A]: E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [4 x 4] - """ - E = ep[0] - A = ep[1] - - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - - Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L - - n = np.asarray(b.T/L).reshape(2,) - - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] - ]) - - return G.T*Kle*G - + ed = [u1 u2] element displacement vector + + OUTPUT: es = [N] element force + ------------------------------------------------------------- -def bar2g(ex, ey, ep, N): - """ - Compute element stiffness matrix for two dimensional geometric - nonlinear bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param float N: normal force - :return mat Ke: stiffness matrix [4 x 4] + LAST MODIFIED: P-E AUSTRELL 1994-11-02 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - E = ep[0] - A = ep[1] + k = ep - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) + N = k*(ed[1]-ed[0]) + es = N - L = np.sqrt(b.T*b).item() + return es - n = np.asarray(b.T/L).reshape(2,) - G = np.mat([ - [n[0], n[1], 0., 0.], - [-n[1], n[0], 0., 0.], - [0., 0., n[0], n[1]], - [0., 0., -n[1], n[0]] - ]) +def bar1e(ex, ep, eq=None): + """ + Ke = bar1e (ex, ep) + Ke, fe = bar1e(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a onedimensional bar element. - Kle = E*A/L*np.mat([ - [1, 0, -1, 0], - [0, 0, 0, 0], - [-1, 0, 1, 0], - [0, 0, 0, 0] - ])+N/L*np.mat([ - [0, 0, 0, 0], - [0, 1, 0, -1], - [0, 0, 0, 0], - [0, -1, 0, 1] - ]) + INPUT: ex = [x1 x2] element node coordinates - return G.T*Kle*G + ep = [E A] element properties; + E: Young's modulus + A: cross section area + ka: axial spring stiffness + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [2 x 2] + fe : element load vector [2 x 1] (if eq!=None) + ------------------------------------------------------------- -def bar2s(ex, ey, ep, ed): - """ - Compute normal force in two dimensional bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, u2, u3, u4] - :return float N: element foce [N] + LAST MODIFIED: O Dahlblom 2015-10-22 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - E = ep[0] - A = ep[1] - - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() + E, A = ep + DEA=E*A - #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L - - n = np.asarray(b.T/L).reshape(2,) + qX=0. + if not eq is None: + qX=eq[0] - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + Ke = DEA/L*np.array([ + [1, -1], + [-1, 1] ]) - - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u - return N.item() + + fe = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + if eq is None: + return Ke + else: + return Ke, fe -def bar3e(ex, ey, ez, ep): +def bar1s(ex, ep, ed, eq=None, nep=None): """ - Compute element stiffness matrix for three dimensional bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [6 x 6] - """ - E = ep[0] - A = ep[1] + es = bar1s(ex, ep, ed) + es = bar1s(ex, ep, ed, eq) + es, edi, eci = bar1s(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional bar element - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() + INPUT: ex = [x1 x2] element node coordinates - n = np.asarray(b.T/L).reshape(3) + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 u2] element displacement vector - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] - ]) + eq = [qX] distributed load - Kle = E*A/L*np.mat([ - [1, -1], - [-1, 1] - ]) + nep : number of evaluation points ( default=2 ) - return G.T*Kle*G + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- -def bar3s(ex, ey, ez, ep, ed): - """ - Compute normal force in three dimensional bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, ..., u6] - :return float N: normal force + LAST MODIFIED: O Dahlblom 2021-02-25 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - E = ep[0] - A = ep[1] + E, A = ep + DEA=E*A + + qX=0. + if not eq is None: + qX=eq[0] + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a1 = ed.reshape(2,1) - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi=u + eci=X - n = np.asarray(b.T/L).reshape(3) + if nep == None: + return es + else: + return es, edi, eci - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] - ]) - #Kle = E*A/L*np.mat([ - # [ 1,-1], - # [-1, 1] - #]) +def bar1we(ex, ep, eq=None): + """ + Ke = bar1we (ex, ep) + Ke, fe = bar1we(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a onedimensional bar element with + axial springs. - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u + INPUT: ex = [x1 x2] element node coordinates - return N.item() + ep = [E A kX] element properties; + E: Young's modulus + A: cross section area + kX: axial spring stiffness -def beam1e(ex, ep, eq=None): - """ - Compute the stiffness matrix for a one dimensional beam element. + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [2 x 2] + fe : element load vector [2 x 1] (if eq!=None) + ------------------------------------------------------------- - :param list ex: element x coordinates [x1, x2] - :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia - :param float eq: distributed load [qy] - :return mat Ke: element stiffness matrix [4 x 4] - :return mat fe: element stiffness matrix [4 x 1] (if eq!=None) + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-10-19 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - L = ex[1]-ex[0] - - E = ep[0] - I = ep[1] + E, A, kX = ep + DEA = E*A; - qy = 0. + qX = 0. if not eq is None: - qy = eq + qX = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) - Ke = E*I/(L**3) * np.mat([ - [12, 6*L, -12, 6*L], - [6*L, 4*L**2, -6*L, 2*L**2], - [-12, -6*L, 12, -6*L], - [6*L, 2*L**2, -6*L, 4*L**2] + K1 = DEA/L*np.array([ + [1, -1], + [-1, 1] ]) - fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T + K2 = kX*L/6*np.array([ + [2, 1], + [1, 2] + ]) + + Ke = K1+K2 + fe = qX*L*np.array([1/2, 1/2]).reshape(2,1) + if eq is None: return Ke else: return Ke, fe -def beam1s(ex, ep, ed, eq=None, nep=None): - """ - Compute section forces in one dimensional beam element (beam1e). - Parameters: +def bar1ws(ex, ep, ed, eq=None, nep=None): + """ + es = bar1ws(ex, ep, ed) + es = bar1ws(ex, ep, ed, eq) + es, edi, eci = bar1ws(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional bar element - ex = [x1 x2] element node coordinates + INPUT: ex = [x1 x2] element node coordinates - ep = [E I] element properties, + ep = [E A kX] element properties, E: Young's modulus - I: moment of inertia - - ed = [u1 ... u4] element displacements - - eq = qy distributed load, local directions - - nep number of evaluation points ( default=2 ) + A: cross section area + kX: axial spring stiffness + + ed = [u1 u2] element displacement vector - Returns: + eq = [qX] distributed load - es = [ V1 M1 section forces, local directions, in - V2 M2 n points along the beam, dim(es)= n x 2 - .........] + nep : number of evaluation points ( default=2 ) - edi = [ v1 element displacements, local directions, - v2 in n points along the beam, dim(es)= n x 1 - .......] + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2021-02-25 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - EI = ep[0]*ep[1] - L = ex[1]-ex[0] - - qy = 0. - - if not eq is None: - qy = eq - + E, A, kX = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a1 = ed.reshape(2,1) - if nep != None: - ne = nep - - Cinv = np.mat([ - [1, 0, 0, 0], - [0, 1, 0, 0], - [-3/(L**2), -2/L, 3/(L**2), -1/L], - [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] - ]) - - Ca = (Cinv@ed).T + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u +kX/DEA*np.concatenate(((X**2-L*X)/2, (X**3-L**2*X)/6),1) @ C1a-(X**2-L*X)*qX/(2*DEA) + du = du +kX/DEA*np.concatenate(((2*X-L)/2, (3*X**2-L**2)/6),1) @ C1a-(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi = u + eci = X - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + if nep == None: + return es + else: + return es, edi, eci - v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ - + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) - d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ - + qy/(2*EI)*(np.power(x,2) - L*x + L**2/12) - d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca - qy*(x - L/2) - M = EI*d2v - V = -EI*d3v - edi = v - eci = x - es = np.concatenate((V, M), 1) +def bar2e(ex, ey, ep, eq=None): + """ + Ke = bar2e(ex, ey, ep) + Ke, fe = bar2e(ex, ey, ep, eq) + ---------------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for two dimensional bar element. + + INPUT: ex = [x1 x2] element node coordinates - return (es, edi, eci) + ey = [y1 y2] element node coordinates + ep = [E A] element properties; + E: Young's modulus + A: cross section area + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [4 x 4] + fe : element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- -def beam2e(ex, ey, ep, eq=None): - """ - Compute the stiffness matrix for a two dimensional beam element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia - :param list eq: distributed loads, local directions [qx, qy] - :return mat Ke: element stiffness matrix [6 x 6] - :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) + LAST MODIFIED: O Dahlblom 2015-10-20 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ + E, A = ep + DEA = E*A - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) - - E = ep[0] - A = ep[1] - I = ep[2] - - qx = 0. - qy = 0. + qX = 0. if not eq is None: - qx = eq[0] - qy = eq[1] - - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], - [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], - [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] - ]) - - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + qX=eq[0] - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + Kle = DEA/L*np.array([ + [1, -1], + [-1, 1] ]) - Ke = G.T*Kle*G - fe = G.T*fle + fle = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + nxX=dx/L + nyX=dy/L + G = np.array([ + [nxX, nyX, 0, 0], + [ 0, 0, nxX, nyX] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle if eq is None: return Ke @@ -462,633 +487,2045 @@ def beam2e(ex, ey, ep, eq=None): return Ke, fe -def beam2s(ex, ey, ep, ed, eq=None, nep=None): +def bar2s(ex, ey, ep, ed, eq=None, nep=None): """ - Compute section forces in two dimensional beam element (beam2e). + es = bar2s(ex, ey, ep, ed) + es = bar2s(ex, ey, ep, ed, eq) + es, edi, eci = bar2s(ex, ey, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in two dimensional bar element. - Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates + INPUT: ex = [x1 x2] element node coordinates - ep = [E A I] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - - ed = [u1 ... u6] element displacements + ey = [y1 y2] element node coordinates - eq = [qx qy] distributed loads, local directions - - nep number of evaluation points ( default=2 ) - - Returns: - - es = [ N1 V1 M1 section forces, local directions, in - N2 V2 M2 n points along the beam, dim(es)= n x 3 - .........] - - edi = [ u1 v1 element displacements, local directions, - u2 v2 in n points along the beam, dim(es)= n x 2 - .......] + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] - - """ - EA = ep[0]*ep[1] - EI = ep[0]*ep[2] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) + eq = [qX] distributed load - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) + nep : number of evaluation points ( default=2 ) - qx = 0. - qy = 0. + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - if not eq is None: - qx = eq[0] - qy = eq[1] + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2015-12-04 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + ne = 2 + if nep != None: + ne=nep - if nep != None: - ne = nep + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 0., 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*L**2, 2*L, 0., 1., 0.] - ]) + nxX = dx/L + nyX = dy/L - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] + G = np.array([ + [nxX, nyX, 0, 0], + [ 0, 0, nxX, nyX] ]) + + a1 = G @ ed.reshape(4,1) - M = np.ravel(C.I*(G*np.asmatrix(ed).T - - np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) - A = np.matrix([M[0], M[3]]).T - B = np.matrix([M[1], M[2], M[4], M[5]]).T - - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T - - u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) - du = np.concatenate((one, zero), 1)*A-x*qx/EA - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, - one), 1)*B+np.power(x, 4)*qy/(24*EI) - d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - B+np.power(x, 2)*qy/(2*EI) - d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI - - N = EA*du - M = EI*d2v - V = -EI*d3v - edi = np.concatenate((u, v), 1) - eci = x - es = np.concatenate((N, V, M), 1) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi = u + eci = X - return (es, edi, eci) + if nep == None: + return es + else: + return es, edi, eci -def beam2t(ex, ey, ep, eq=None): +def bar2ge(ex, ey, ep, QX): """ - Compute the stiffness matrix for a two dimensional elastic - Timoshenko beam element. - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates - - ep = [E G A I ks] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - I: Moment of inertia - ks: Shear correction factor - - eq = [qx qy] distributed loads, local directions - - Returns: - - Ke element stiffness matrix (6 x 6) - - fe element load vector (6 x 1) + Ke = bar2ge(ex, ey, ep, QX) + ---------------------------------------------------------------------- + PURPOSE + Compute element stiffness matrix for two dimensional geometric + nonlinear bar element. - """ + INPUT: ex = [x1 x2] element node coordinates - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) + ey = [y1 y2] element node coordinates - E = ep[0] - Gm = ep[1] - A = ep[2] - I = ep[3] - ks = ep[4] + ep = [E A] element properties; + E: Young's modulus + A: cross section area - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] - - m = (12/L**2)*(E*I/(Gm*A*ks)) - - Kle = E/(1+m)*np.mat([ - [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], - [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], - [0., 6*I/L**2., 4*I * - (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], - [-A*(1+m)/L, 0., 0., - A*(1+m)/L, 0., 0.], - [0., -12*I/L**3., -6*I/L**2., - 0., 12*I/L**3., -6*I/L**2.], - [0., 6*I/L**2., 2*I * - (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] - ]) + QX: axial force in the bar + + OUTPUT: Ke : bar stiffness matrix [4 x 4] + ------------------------------------------------------------- - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA = E*A - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0le = DEA/L*np.array([ + [ 1, 0, -1, 0], + [ 0, 0, 0, 0], + [-1, 0, 1, 0], + [ 0, 0, 0, 0] + ]) + + Ksle = QX/L*np.array([ + [ 0, 0, 0, 0], + [ 0, 1, 0, -1], + [ 0, 0, 0, 0], + [ 0, -1, 0, 1] ]) - Ke = G.T*Kle*G - fe = G.T*fle - - if eq is None: - return Ke - else: - return Ke, fe + Kle = K0le + Ksle + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L -def beam2ts(ex, ey, ep, ed, eq=None, nep=None): - """ - Compute section forces in two dimensional beam element (beam2e). - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + G = np.array([ + [nxX, nyX, 0, 0], + [nxY, nyY, 0, 0], + [ 0, 0, nxX, nyX], + [ 0, 0, nxY, nyY] + ]) - ep = [E,G,A,I,ks] element properties, - E: Young's modulus - G: shear modulus - A: cross section area - I: moment of inertia + Ke = G.T @ Kle @ G - ed = [u1, ... ,u6] element displacements + return Ke - eq = [qx, qy] distributed loads, local directions - nep number of evaluation points ( default=2 ) - - Returns: - - es = [[N1,V1,M1], section forces, local directions, in - [N2,V2,M2], n points along the beam, dim(es)= n x 3 - ..........] - - edi = [[u1,v1,teta1], element displacements, local directions, - [u2,v2,teta2], and rotation of cross section at - .............] in n points along the beam, dim(es)= n x 2 - - (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) - - eci = [[x1], local x-coordinates of the evaluation - [x2], points, (x1=0 and xn=L) - ....] - +def bar2gs(ex, ey, ep, ed, nep=None): """ - EA = ep[0]*ep[2] - EI = ep[0]*ep[3] - GAK = ep[1]*ep[2]*ep[4] - alfa = EI/GAK - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) - - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] + es, QX, edi, eci = bar2s(ex, ey, ep, ed) + es, QX, edi, eci = bar2s(ex, ey, ep, ed, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in two dimensional bar element (bar2ge). + + INPUT: ex = [x1 x2] element node coordinates - ne = 2 + ey = [y1 y2] element node coordinates - if nep != None: - ne = nep + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 6*alfa, 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] - ]) + nep : number of evaluation points ( default=2 ) - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + QX: axial force - M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( - 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) - C2 = np.mat([M[0], M[3]]).T - C4 = np.mat([M[1], M[2], M[4], M[5]]).T + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) - du = np.concatenate((one, zero), 1)*C2-qx*x/EA + LAST MODIFIED: O Dahlblom 2015-10-20 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA = E*A + + ne=2 + if nep != None: + ne=nep - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ - C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) - dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), - 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), - 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) - dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - C4+qy*np.power(x, 2)/(2*EI) + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L - N = EA*du - M = EI*dteta - V = GAK*(dv-teta) + G = np.array([ + [nxX, nyX, 0, 0], + [nxY, nyY, 0, 0], + [ 0, 0, nxX, nyX], + [ 0, 0, nxY, nyY] + ]) + + edl = G @ ed.reshape(4,1) + a1 = np.array([ + edl[0], + edl[2] + ]) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 - es = np.concatenate((N, V, M), 1) - edi = np.concatenate((u, v, teta), 1) - eci = x + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + N = DEA*du + QX = N[0] + es = N + edi=u + eci=X - if nep != None: - return es, edi, eci + if nep == None: + return es, QX else: - return es + return es, QX, edi, eci -def beam2w(ex, ey, ep, eq=None): +def bar3e(ex, ey, ez, ep, eq=None): """ - Compute the stiffness matrix for a two dimensional beam element - on elastic foundation. + Ke = bar2e(ex, ey, ez, ep) + Ke, fe = bar2e(ex, ey, ez, ep, eq) + ---------------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for three dimensional bar element. - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] - eq = [qx, qy] distributed loads, local directions + ep = [E A] element properties; + E: Young's modulus + A: cross section area - Returns: + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - Ke beam stiffness matrix (6 x 6) - - fe element load vector (6 x 1) + LAST MODIFIED: O Dahlblom 2015-10-19 + O Dahlblom 2022-11-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2) - - E, A, I, ka, kt = ep + E, A = ep + DEA=E*A - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq - - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + qX=0. + if not eq is None: + qX=eq[0] - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) + + Kle = DEA/L*np.array([ + [1, -1], + [-1, 1] ]) - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T - - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] + fle = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + nxX=dx/L + nyX=dy/L + nzX=dz/L + G = np.array([ + [nxX, nyX, nzX, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, nzX] ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle - Ke = G.T*Kle*G - fe = G.T*fle - - if eq != None: - return Ke, fe - else: + if eq is None: return Ke + else: + return Ke, fe -def beam2ws(ex, ey, ep, ed, eq=None): +def bar3s(ex, ey, ez, ep, ed, eq=None, nep=None): """ - Compute section forces in a two dimensional beam element - on elastic foundation. + es = bar3s(ex, ey, ez, ep, ed) + es = bar3s(ex, ey, ez, ep, ed, eq) + es, edi, eci = bar3s(ex, ey, ez, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in three dimensional bar element. - Parameters: + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] + + ep = [E A] element properties, + E: Young's modulus + A: cross section area - ex = [x1, x2] - ey = [y1, y2] element node coordinates + ed = [u1 ... u4] element displacement vector - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness + eq = [qX] distributed load - ed = [u1, ... ,u6] element displacement vector + nep : number of evaluation points ( default=2 ) - eq = [qx, qy] distributed loads, local directions + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - Returns: + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - es = [[N1, V1, M1], - [N2, V2, M2]] element forces, local direction + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-11-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - if np.asmatrix(ed).shape[0] > 1: - error("Only one row is allowed in the ed matrix !!!") - return + E, A = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + + ne = 2 + if nep != None: + ne = nep - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) + + nxX = dx/L + nyX = dy/L + nzX =dz/L + + G = np.array([ + [nxX, nyX, nzX, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, nzX] ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + + a1 = G @ ed.reshape(6,1) - E, A, I, ka, kt = ep + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi=u + eci=X - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + if nep == None: + return es + else: + return es, edi, eci + + +def beam1e(ex, ep, eq=None): + """ + Ke = beam1e(ex, ep) + Ke, fe = beam1e(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a one dimensional beam element. + + INPUT: ex = [x1 x2] element node coordinates + + ep = [E I] element properties; + E: Young's modulus + I: moment of inertia + + eq = [qY] distributed load + + OUTPUT: Ke : beam stiffness matrix [4 x 4] + fe : element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2019-01-09 + O Dahlblom 2022-10-25 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, I = ep + DEI = E*I + + qY = 0. + if not eq is None: + qY = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + Ke = DEI/L**3*np.array([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + fe = qY*np.array([L/2, L**2/12, L/2, -L**2/12]).reshape(4,1) + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam1s(ex, ep, ed, eq=None, nep=None): + """ + es = beam1s(ex, ep, ed) + es = beam1s(ex, ep, ed, eq) + es, ed, ec = beam1s(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional beam element (beam1e). + + INPUT ex = [x1 x2] element node coordinates + + ep = [E I] element properties, + E: Young's modulus + I: moment of inertia + + ed = [u1 ... u4] element displacements + + eq = [qy] distributed loads, local directions + + nep : number of evaluation points ( default=2 ) + + OUTPUT: es = [V1 M1 ; section forces, local directions, in + V2 M2 ; nep points along the beam, dim(es)= nep x 2 + ......] + + edi = [v1 ; element displacements, local directions, + v2 ; in nep points along the beam, dim(edi)= nep x 1 + ....] + + eci = [x1; evaluation points on the local x-axis + x2; + ..] + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-10-25 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + + E, I = ep + DEI = E*I + + qY=0. + + if not eq is None: + qY = eq[0] + + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a2 = ed.reshape(4,1) + + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) +# dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v+(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v+(2*X - L*one)*qY/(2*DEI) + + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((V, M), 1) + edi = v + eci = X + + if nep == None: + return es + else: + return es, edi, eci + + +def beam1we(ex, ep, eq=None): + """ + Ke = beam1we(ex, ep) + Ke, fe = beam1we(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a one dimensional beam element + on elastic foundation. + + INPUT: ex = [x1 x2] element node coordinates + + ep = [E I kY] element properties; + E: Young's modulus + I: moment of inertia + kY: transversal found. stiffness + + eq = [qY] distributed load + + OUTPUT: Ke: beam stiffness matrix [4 x 4] + fe: element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2016-02-17 + O Dahlblom 2022-10-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, I, kY =ep + DEI = E*I; + + qY = 0 + if not eq is None: + qY = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + K0 = DEI/L**3*np.array([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + Ks = kY*L/420*np.array([ + [156, 22*L, 54, -13*L], + [22*L, 4*L**2, 13*L, -3*L**2], + [54, 13*L, 156, -22*L], + [-13*L, -3*L**2, -22*L, 4*L**2] + ]) + + Ke = K0+Ks + + fe = qY*np.array([L/2, L**2/12, L/2, -L**2/12]).reshape(4,1) + if eq is None: + return Ke + else: + return Ke, fe + + +def beam1ws(ex, ep, ed, eq=None, nep=None): + """ + es = beam1ws(ex, ep, ed) + es = beam1ws(ex, ep, ed, eq) + es, ed, ec = beam1ws(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional beam element + on elastic foundation (beam1we). + + INPUT: ex = [x1 x2] element node coordinates + + ep = [E I kY] element properties, + E: Young's modulus + I: moment of inertia + kY: transversal foundation stiffness + + ed = [u1 ... u4] element displacements + + eq = [qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [V1 M1 ; section forces, local directions, in + V2 M2 ; nep points along the beam, dim(es)= n x 2 + ......] + + edi = [v1 ; element displacements, local directions, + v2 ; in nep points along the beam, dim(edi)= n x 1 + ...] + + eci = [x1 ; evaluation points on the local x-axis + x2 ; + ...] + + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-10-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, I, kY = ep + DEI = E*I + + qY = 0. + + if not eq is None: + qY = eq[0] + + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a2 = ed.reshape(4,1) + + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + + if DEI != 0: + v = v - kY/DEI*np.concatenate(( + (X**4 - 2*L*X**3 + L**2*X**2)/24, + (X**5 - 3*L**2*X**3 + 2*L**3*X**2)/120, + (X**6 - 4*L**3*X**3 + 3*L**4*X**2)/360, + (X**7 - 5*L**4*X**3 + 4*L**5*X**2)/840), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + d2v = d2v - kY/DEI*np.concatenate(( + (6*X**2 - 6*L*X + L**2*one)/12, + (10*X**3 - 9*L**2*X + 2*L**3*one)/60, + (5*X**4 - 4*L**3*X + L**4*one)/60, + (21*X**5 - 15*L**4*X + 4*L**5*one)/420),1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v - kY/DEI*np.concatenate(( + (2*X - L*one)/2, + (10*X**2 - 3*L**2)/20, + (5*X**3 - L**3*one)/15, + (7*X**4 - L**4*one)/28), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((V, M), 1) + edi = v + eci = X + + if nep == None: + return es + else: + return es, edi, eci + + +def beam2e(ex, ey, ep, eq=None): + """ + Ke = beam2e(ex, ey, ep) + Ke, fe = beam2e(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional beam element. + + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E A I] element properties; + E: Young's modulus + A: Cross section area + I: moment of inertia + + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2015-08-17 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + Kle = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2, 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) + + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2s(ex, ey, ep, ed, eq=None, nep=None): + """ + es = beam2s(ex, ey, ep, ed) + es = beam2s(ex, ey, ep, ed, eq) + es, edi, eci = beam2s(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in two dimensional beam element (beam2e). + + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E A I] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1 ... u6] element displacements + + eq = [qx qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + LAST MODIFIED: O Dahlblom 2021-09-08 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + edl = G @ ed.reshape(6,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v=np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) +# dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v+(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v+(2*X - L*one)*qY/(2*DEI) + + N = DEA*du + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es + else: + return es, edi, eci + + +def beam2we(ex, ey, ep, eq=None): + """ + Ke = beam2we(ex, ey, ep) + Ke, fe = beam2we(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional beam element + on elastic foundation. + + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E,A,I,kX,kY] element properties; + E: Young's modulus + A: Cross section area + I: moment of inertia + kX: axial foundation stiffness + kY: transversal foundation stiffness + + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2015-08-07 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I, kX, kY = ep + DEA = E*A + DEI = E*I + + qX = 0 + qY = 0 + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0 = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2., 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) + + Ks = L/420*np.array([ + [140*kX, 0, 0, 70*kX, 0, 0], + [0, 156*kY, 22*kY*L, 0, 54*kY, -13*kY*L], + [0, 22*kY*L, 4*kY*L**2, 0, 13*kY*L, -3*kY*L**2], + [70*kX, 0, 0, 140*kX, 0, 0], + [0, 54*kY, 13*kY*L, 0, 156*kY, -22*kY*L], + [0, -13*kY*L, -3*kY*L**2, 0, -22*kY*L, 4*kY*L**2] + ]) + + Kle = K0+Ks + + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2ws(ex, ey, ep, ed, eq=None, nep=None): + """ + es = beam2ws(ex, ey, ep, ed) + es = beam2ws(ex, ey, ep, ed, eq) + es, edi, eci = beam2ws(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in a two dimensional beam element + on elastic foundation. + + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E,A,I,kX,kY] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + kX: axial foundation stiffness + kY: transversal foundation stiffness + + ed = [u1 ... u6] element displacements + + eq = [qx qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2022-09-30 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I, kX, kY = ep + DEA = E*A + DEI = E*I + + qX = 0 + qY = 0 + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + ne = 2 + if nep != None: + ne = nep + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + edl = G @ ed.reshape(6,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u +kX/DEA*np.concatenate(((X**2-L*X)/2, (X**3-L**2*X)/6),1) @ C1a-(X**2-L*X)*qX/(2*DEA) + du = du +kX/DEA*np.concatenate(((2*X-L)/2, (3*X**2-L**2)/6),1) @ C1a-(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v - kY/DEI*np.concatenate(( + (X**4 - 2*L*X**3 + L**2*X**2)/24, + (X**5 - 3*L**2*X**3 + 2*L**3*X**2)/120, + (X**6 - 4*L**3*X**3 + 3*L**4*X**2)/360, + (X**7 - 5*L**4*X**3 + 4*L**5*X**2)/840), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + d2v = d2v - kY/DEI*np.concatenate(( + (6*X**2 - 6*L*X + L**2*one)/12, + (10*X**3 - 9*L**2*X + 2*L**3*one)/60, + (5*X**4 - 4*L**3*X + L**4*one)/60, + (21*X**5 - 15*L**4*X + 4*L**5*one)/420),1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v - kY/DEI*np.concatenate(( + (2*X - L*one)/2, + (10*X**2 - 3*L**2)/20, + (5*X**3 - L**3*one)/15, + (7*X**4 - L**4*one)/28), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + + N = DEA*du + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es + else: + return es, edi, eci + + +def beam2ge(ex, ey, ep, QX, eq=None): + """ + Ke = beam2ge(ex, ey, ep, QX) + Ke, fe = beam2ge(ex, ey, ep, QX, eq) + ------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + QX axial force in the beam + + eq = [qY] distributed transverse load + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0le = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2, 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) + + Ksle = QX/(30*L)*np.array([ + [ 0., 0., 0., 0., 0., 0.], + [ 0., 36., 3*L, 0., -36., 3*L], + [ 0., 3*L, 4*L**2, 0., -3*L, -L**2], + [ 0., 0., 0., 0., 0., 0.], + [ 0., -36., -3*L, 0., 36., -3*L], + [ 0., 3*L, -L**2, 0., -3*L, 4*L**2] + ]) + + fle = qY*L*np.array([0, 1/2, L/12, 0, 1/2, -L/12]).reshape(6,1) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Kle = K0le+Ksle + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2gs(ex, ey, ep, ed, QX, eq=None, nep=None): + """ + es, QX = beam2gs(ex, ey, ep, ed, QX) + es, QX = beam2gs(ex, ey, ep, ed, QX, eq) + es, QX, edi, eci = beam2gs(ex, ey, ep, ed, QX, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Calculate section forces in a two dimensional nonlinear + beam element (beam2ge). + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacement vector + + QX axial force + + eq = [qy] distributed transverse load + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + QX axial force + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + ne = 2 + if nep != None: + ne = nep + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + edl = G @ ed.reshape(6,1) + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v + QX/DEI*np.concatenate((zero, zero, (X**4-2*L*X**3+L**2*X**2)/12, (X**5-3*L**2*X**3+2*L**3*X**2)/20), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + dv = dv + QX/DEI*np.concatenate((zero, zero, (2*X**3-3*L*X**2+L**2*X)/6, (5*X**4-9*L**2*X**2+4*L**3*X)/20), 1) @ C2a + \ + (2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v + QX/DEI*np.concatenate((zero, zero, (6*X**2-6*L*X+L**2*one)/6, (10*X**3-9*L**2*X+2*L**3*one)/10), 1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v + QX/DEI*np.concatenate((zero, zero, (2*X-L*one), (30*X**2-9*L**2*one)/10), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + + QX = DEA*du.item(0) + M = DEI*d2v + V = -DEI*d3v + N=QX+dv*V + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es, QX + else: + return es, QX, edi, eci + + +def beam2gxe(ex, ey, ep, QX, eq=None): + """ + Ke = beam2gxe(ex, ey, ep, QX) + Ke, fe = beam2gxe(ex, ey, ep, QX, eq) + ------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity with exact solution. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + QX axial force in the beam + + eq distributed transverse load + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-06-21 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + eps = 1e-12 + + if QX < -eps*DEI/L**2: + kL = np.sqrt(-QX/DEI)*L + f1 = (kL/2)/np.tan(kL/2) + f2 = kL**2/(12*(1-f1)) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif QX > eps*DEI/L**2: + kL = np.sqrt(QX/DEI)*L + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 + + Kle = np.array([ + [DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI*f5/L**3, 6*DEI*f2/L**2, 0., -12*DEI*f5/L**3, 6*DEI*f2/L**2], + [ 0., 6*DEI*f2/L**2, 4*DEI*f3/L, 0., -6*DEI*f2/L**2, 2*DEI*f4/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI*f5/L**3, -6*DEI*f2/L**2, 0., 12*DEI*f5/L**3, -6*DEI*f2/L**2], + [0., 6*DEI*f2/L**2, 2*DEI*f4/L, 0., -6*DEI*f2/L**2, 4*DEI*f3/L] + ]) + + fle = qY*L*np.array([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).reshape(6,1) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2gxs(ex, ey, ep, ed, QX, eq=None, nep=None): + """ + es, QX = beam2gxs(ex, ey, ep, ed, QX) + es, QX = beam2gxs(ex, ey, ep, ed, QX, eq) + es, QX, edi, eci = beam2gxs(ex, ey, ep, ed, QX, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Calculate section forces in a two dimensional nonlinear + beam element (beam2gxe). + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacement vector + + QX axial force + + eq = [qy] distributed transverse load + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + QX axial force + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-09-17 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + ne = 2 + if nep != None: + ne = nep + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + edl = G @ ed.reshape(6,1) + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] ]) - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] - ]) + eps = 1e-12 + + if QX < -eps*DEI/L**2: + k = np.sqrt(-QX/DEI) + kL = k*L + C2 = 1/(k*(-2*(1-np.cos(kL))+kL*np.sin(kL)))*np.array([ + [k*(kL*np.sin(kL)+np.cos(kL)-1), -kL*np.cos(kL)+np.sin(kL), -k*(1-np.cos(kL)), -np.sin(kL)+kL], + [-(k**2)*np.sin(kL), -k*(1-np.cos(kL)), (k**2)*np.sin(kL), -k*(1-np.cos(kL))], + [-k*(1-np.cos(kL)), kL*np.cos(kL)-np.sin(kL), k*(1-np.cos(kL)), np.sin(kL)-kL], + [k*np.sin(kL), (kL*np.sin(kL)+np.cos(kL)-1), -k*np.sin(kL), (1-np.cos(kL))] + ]) + + C2a = C2 @ a2 + v = np.concatenate((one, X, np.cos(k*X), np.sin(k*X)), 1) @ C2a + dv = np.concatenate((zero, one, -k*np.sin(k*X), k*np.cos(k*X)), 1) @ C2a + d2v = np.concatenate((zero, zero, -k**2*np.cos(k*X), -k**2*np.sin(k*X)), 1) @ C2a + d3v = np.concatenate((zero, zero, k**3*np.sin(k*X), -k**3*np.cos(k*X)), 1) @ C2a + if DEI != 0: + v = v+qY*L**4/(2*DEI)*((1+np.cos(kL))/(kL**3*np.sin(kL))*(-1+np.cos(k*X))+np.sin(k*X)/kL**3+X*(-1+X/L)/(kL**2*L)) + dv = dv+qY*L**3/(2*DEI)*((1+np.cos(kL))/(kL**2*np.sin(kL))*(-np.sin(k*X))+np.cos(k*X)/kL**2+(-1+2*X/L)/kL**2) + d2v = d2v+qY*L**2/(2*DEI)*((1+np.cos(kL))/(kL*np.sin(kL))*(-np.cos(k*X))-np.sin(k*X)/kL+2/(kL**2)) + d3v = d3v+qY*L/(2*DEI)*((1+np.cos(kL))/np.sin(kL)*(np.sin(k*X))-np.cos(k*X)) + elif QX > eps*DEI/L**2: + k = np.sqrt(QX/DEI) + kL = k*L + C2 = 1/(k*(-2*(1-np.cosh(kL))-kL*np.sinh(kL)))*np.array([ + [k*(-kL*np.sinh(kL)+np.cosh(kL)-1), -kL*np.cosh(kL)+np.sinh(kL), -k*(1-np.cosh(kL)), -np.sinh(kL)+kL], + [(k**2)*np.sinh(kL), -k*(1-np.cosh(kL)), -(k**2)*np.sinh(kL), -k*(1-np.cosh(kL))], + [-k*(1-np.cosh(kL)), kL*np.cosh(kL)-np.sinh(kL), k*(1-np.cosh(kL)), np.sinh(kL)-kL], + [-k*np.sinh(kL), (-kL*np.sinh(kL)+np.cosh(kL)-1), k*np.sinh(kL), (1-np.cosh(kL))] + ]) + C2a = C2 @ a2 + v = np.concatenate((one, X, np.cosh(k*X), np.sinh(k*X)), 1) @ C2a + dv = np.concatenate((zero, one, k*np.sinh(k*X), k*np.cosh(k*X)), 1) @ C2a + d2v = np.concatenate((zero, zero, k**2*np.cosh(k*X), k**2*np.sinh(k*X)), 1) @ C2a + d3v = np.concatenate((zero, zero, k**3*np.sinh(k*X), k**3*np.cosh(k*X)), 1) @ C2a + if DEI != 0: + v = v+qY*L**4/(2*DEI)*((1+np.cosh(kL))/(kL**3*np.sinh(kL))*(-1+np.cosh(k*X))-np.sinh(k*X)/kL**3+X*(1-X/L)/(kL**2*L)) + dv = dv+qY*L**3/(2*DEI)*((1+np.cosh(kL))/(kL**2*np.sinh(kL))*(np.sinh(k*X))-np.cosh(k*X)/kL**2+(1-2*X/L)/kL**2) + d2v = d2v+qY*L**2/(2*DEI)*((1+np.cosh(kL))/(kL*np.sinh(kL))*(np.cosh(k*X))-np.sinh(k*X)/kL-2/(kL**2)) + d3v = d3v+qY*L/(2*DEI)*((1+np.cosh(kL))/np.sinh(kL)*(np.sinh(k*X))-np.cosh(k*X)) + else: + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + dv = dv+(2*X**3 -3*L*X**2 +L**2*X)*qY/(12*DEI) + d2v = d2v +(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v +(2*X - L*one)*qY/(2*DEI) + + QX = DEA*du.item(0) + M = DEI*d2v + V = -DEI*d3v + N=QX+dv*V + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es, QX + else: + return es, QX, edi, eci + + +def beam2te(ex, ey, ep, eq=None): + """ + Ke = beam2te(ex, ey, ep) + Ke, fe = beam2te(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional Timoshenko + beam element. + + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E Gm A I ks] element properties; + E: Young's modulus + G: shear modulus + A: Cross section area + I: moment of inertia + ks: shear correction factor + + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2021-11-05 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, Gm, A, I, ks = ep + DEA = E*A + DEI = E*I + DGAks = Gm*A*ks + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + m = (12*DEI)/(L**2*DGAks) + f1=1/(1+m) + f2=f1*(1+m/4) + f3=f1*(1-m/2) - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] + Kle = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI*f1/L**3, 6*DEI*f1/L**2, 0., -12*DEI*f1/L**3, 6*DEI*f1/L**2], + [ 0., 6*DEI*f1/L**2, 4*DEI*f2/L, 0., -6*DEI*f1/L**2, 2*DEI*f3/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI*f1/L**3, -6*DEI*f1/L**2, 0., 12*DEI*f1/L**3, -6*DEI*f1/L**2], + [ 0., 6*DEI*f1/L**2, 2*DEI*f3/L, 0., -6*DEI*f1/L**2, 4*DEI*f2/L] ]) - P = Kle*G*np.asmatrix(ed).T-fle + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] ]) - return es + Ke = G.T @ Kle @ G + fe = G.T @ fle + if eq is None: + return Ke + else: + return Ke, fe + -def beam2g(ex, ey, ep, N, eq=None): +def beam2ts(ex, ey, ep, ed, eq=None, nep=None): """ - Compute the element stiffness matrix for a two dimensional - beam element with respect to geometric nonlinearity. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + es = beam2ts(ex, ey, ep, ed) + es = beam2ts(ex, ey, ep, ed, eq) + es, edi, eci = beam2s(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in two dimensional Timoshenko beam + element (beam2te). - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates - N axial force in the beam + ep = [E G A I ks] element properties, + E: Young's modulus + G: shear modulus + A: cross section area + I: moment of inertia + ks: shear correction factor - eq distributed transverse load + ed = [u1 ... u6] element displacements - Returns: + eq = [qx qy] distributed loads, local directions - Ke element stiffness matrix (6 x 6) + nep number of evaluation points ( default=2 ) - fe element load vector (6 x 1) - """ - if eq != None: - if np.size(eq) > 1: - error("eq should be a scalar !!!") - return - else: - q = eq[0] - else: - q = 0 + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 teta1 element displacements, local directions, + u2 v2 teta2 in n points along the beam, dim(es)= n x 2 + ...........] + (Note! For Timoshenko beam element the rotation of the cross + section is not equal to dv/dx) + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + LAST MODIFIED: O Dahlblom 2021-11-05 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, Gm, A, I, ks = ep + DEA = E*A + DEI = E*I + DGAks = Gm*A*ks + alpha=DEI/DGAks + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq - E, A, I = ep + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - rho = -N*L**2/(np.pi**2*E*I) + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps + edl = G @ ed.reshape(6,1) - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) - else: - f1 = f2 = f3 = f4 = f5 = h = 1 + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., - 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 4*E*I*f3/L, - 0., -6*E*I*f2/L**2., 2*E*I*f4/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., - 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 2*E*I*f4/L, - 0., -6*E*I*f2/L**2., 4*E*I*f3/L] + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] ]) + C2 = 1/(L**2+12*alpha)*np.array([ + [L**2+12*alpha, 0., 0., 0.], + [ -12*alpha/L, L**2+6*alpha, 12*alpha/L, -6*alpha], + [ -3., -2*L-6*alpha/L, 3., -L+6*alpha/L], + [ 2/L, 1., -2/L, 1.] + ]) + C2a = C2 @ a2 - fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + theta = np.concatenate((zero, one, 2*X, 3*X**2+6*alpha), 1) @ C2a + dtheta=np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI)+(-X**2/2+L*X/2)*qY/DGAks + dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI)+(-X+L/2)*qY/DGAks + theta = theta+(2*X**3-3*L*X**2+L**2*X)*qY/(12*DEI) + dtheta = dtheta+(6*X**2-6*L*X+L**2)*qY/(12*DEI) - Ke = G.T*Kle*G - fe = G.T*fle + N = DEA*du + M = DEI*dtheta + V = DGAks*(dv-theta) + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v, theta), 1) + eci = X - if eq != None: - return Ke, fe + if nep == None: + return es else: - return Ke - + return es, edi, eci + -def beam2gs(ex, ey, ep, ed, N, eq=None): +def beam2de(ex, ey, ep): """ - Calculate section forces in a two dimensional nonlinear + Ke, Me = beam2de(ex, ey, ep) + Ke, Me, Ce = beam2de(ex, ey, ep) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix Ke, the mass matrix Me + and the damping matrix Ce for a 2D elastic Bernoulli beam element. - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia - - ed = [u1, ... ,u6] element displacement vector - - N axial force + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - eq = [qy] distributed transverse load + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe - Returns: + OUTPUT: Ke element stiffness matrix (6 x 6) + Me element mass martix + Ce element damping matrix, optional + ------------------------------------------------------------- - es = [[N1,V1,M1], element forces, local directions - [N2,V2,M2]] + LAST MODIFIED: K Persson 1995-08-23 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - if eq != None: - eq = eq[0] - else: - eq = 0 - - b = np.mat([ + b = np.array([ [ex[1]-ex[0]], [ey[1]-ey[0]] ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + L = np.sqrt(b.T @ b).item(0) + n = np.array(b/L).reshape(2,) - E, A, I = ep + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep - rho = -N*L**2/(np.pi**2*E*I) + print ("E, A, I, m, a, b, L") + print (E, A, I, m, a, b, L) - eps = 2.2204e-16 - kL = np.pi*np.sqrt(abs(rho))+eps - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) - else: - f1 = f2 = f3 = f4 = f5 = h = 1 + Kle = np.array([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) - Kle = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, - 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, - 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] + Mle = m*L/420*np.array([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] ]) - fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T + Cle = a*Mle+b*Kle - G = np.mat([ + G = np.array([ [n[0], n[1], 0, 0, 0, 0], [-n[1], n[0], 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], @@ -1097,48 +2534,59 @@ def beam2gs(ex, ey, ep, ed, N, eq=None): [0, 0, 0, 0, 0, 1] ]) - u = np.asmatrix(ed).T - P = Kle*G*u-fle - - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] - ]) + Ke = G.T @ Kle @ G + Me = G.T @ Mle @ G + Ce = G.T @ Cle @ G - return es + if np.size(ep) == 4: + return Ke, Me + elif np.size(ep) == 6: + return Ke, Me, Ce -def beam2d(ex, ey, ep): +def beam2ds(ex, ey, ep, ed, ev, ea): """ - Calculate the stiffness matrix Ke, the mass matrix Me - and the damping matrix Ce for a 2D elastic Bernoulli - beam element. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,m,(a,b)] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia - m: mass per unit length - a,b: damping coefficients, - Ce=aMe+bKe + es = beam2ds(ex, ey, ep, ed, ev, ea) + ------------------------------------------------------------- + PURPOSE + Calculate the element forces for a number of identical + (nie) 2D Bernoulli beam elements in dynamic analysis. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe + + ed : element displacement matrix + + ev : element velocity matrix + + ea : element acceleration matrix - Returns: + OUTPUT: es : element forces in local directions, + = [-N1 -V1 -M1 N2 V2 M2; + ....... ......] ; dim(es)= nie x 6 + ------------------------------------------------------------- - Ke element stiffness matrix (6 x 6) - Me element mass martix - Ce element damping matrix, optional + LAST MODIFIED: K Persson 1995-08-23 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - b = np.mat([ + b = np.array([ [ex[1]-ex[0]], [ey[1]-ey[0]] ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + L = np.sqrt(b.T @ b).item(0) + n = np.array(b/L).reshape(2,) a = 0 b = 0 @@ -1147,7 +2595,7 @@ def beam2d(ex, ey, ep): elif np.size(ep) == 6: E, A, I, m, a, b = ep - Kle = np.mat([ + Kle = np.array([ [E*A/L, 0, 0, -E*A/L, 0, 0], [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], @@ -1156,7 +2604,7 @@ def beam2d(ex, ey, ep): [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] ]) - Mle = m*L/420*np.mat([ + Mle = m*L/420*np.array([ [140, 0, 0, 70, 0, 0], [0, 156, 22*L, 0, 54, -13*L], [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], @@ -1167,7 +2615,7 @@ def beam2d(ex, ey, ep): Cle = a*Mle+b*Kle - G = np.mat([ + G = np.array([ [n[0], n[1], 0, 0, 0, 0], [-n[1], n[0], 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], @@ -1176,14 +2624,22 @@ def beam2d(ex, ey, ep): [0, 0, 0, 0, 0, 1] ]) - Ke = G.T*Kle*G - Me = G.T*Mle*G - Ce = G.T*Cle*G + nie, ned = ed.shape + es = np.array(np.zeros((nie, 6))) + for i in range(nie): + d = ed[i,:].reshape(6,1) + v = ev[i,:].reshape(6,1) + a = ea[i,:].reshape(6,1) + es[i,:] = (Kle @ G @ d + Cle @ G @ v + Mle @ G @ a).T + +# [nie,ned]=size(ed); +# for i=1:nie +# d=ed(i,:)'; +# v=ev(i,:)'; +# a=ea(i,:)'; +# es(i,:)=(Kle*G*d+Cle*G*v+Mle*G*a)'; - if np.size(ep) == 4: - return Ke, Me - elif np.size(ep) == 6: - return Ke, Me, Ce + return es def beam3e(ex, ey, ez, eo, ep, eq=None): @@ -1363,7 +2819,6 @@ def beam3s(ex, ey, ez, eo, ep, ed, eq=None, nep=None): [xn]] ------------------------------------------------------------- - LAST MODIFIED: O Dahlblom 2015-10-19 O Dahlblom 2022-11-23 (Python version) Copyright (c) Division of Structural Mechanics and @@ -1519,7 +2974,7 @@ def beam3s(ex, ey, ez, eo, ep, ed, eq=None, nep=None): return es else: return es, edi, eci - + def flw2te(ex, ey, ep, D, eq=None): """ @@ -3983,6 +5438,412 @@ def eigen(K,M,b=None): return L, X +def gfunc(G,dt): + """ + Form vector with function values at equally spaced + points by linear interpolation + + Parameters: + + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step + + Returns: + + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 + + +def step1(K,C,f,a0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. + + Parameters: + + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta are: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + if not np.array(C).any(): + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + def extract_eldisp(edof, a): """ Extract element displacements from the global displacement @@ -4466,4 +6327,4 @@ def beam2crd(ex=None, ey=None, ed=None, mag=None): excd[i, :] = xyc[0, :]+mag*cd[0, :] eycd[i, :] = xyc[1, :]+mag*cd[1, :] - return excd, eycd + return excd, eycd \ No newline at end of file diff --git a/calfem/core_compat.py b/calfem/core_compat.py new file mode 100644 index 0000000..901803b --- /dev/null +++ b/calfem/core_compat.py @@ -0,0 +1,4877 @@ +# -*- coding: iso-8859-15 -*- +""" +CALFEM Core module + +Contains all the functions implementing CALFEM standard functionality +""" + +from scipy.sparse.linalg import dsolve +from scipy.linalg import eig, lu +import numpy as np + +import logging as cflog +import sys +import traceback + +__prev_exception_hook = sys.excepthook + + +def exception_logging(exctype, value, tb): + """ + Log exception by using the root logger. + + Parameters + ---------- + exctype : type + value : NameError + tb : traceback + """ + write_val = {'exception_type': str(exctype), + 'message': str(traceback.format_tb(tb, 10))} + print('Error: %s \n in "%s", line %d' % + (value, tb.tb_frame.f_code.co_filename, tb.tb_lineno)) + + +def enable_friendly_errors(): + __prev_exception_hook = sys.excepthook + sys.excepthook = exception_logging + + +def disable_friendly_errors(): + sys.excepthook = __prev_exception_hook + + +easy_on = enable_friendly_errors +easy_off = disable_friendly_errors + + +def check_list_array(v, error_string): + + fname = sys._getframe(1).f_code.co_name + + if (type(v) != list) and (type(v) != np.ndarray): + raise TypeError("%s (%s)" % (error_string, fname)) + + +def check_length(v, length, error_string): + + fname = sys._getframe(1).f_code.co_name + + if len(v) != length: + raise ValueError("%s (%s)" % (error_string, fname)) + + +def user_warning(msg): + + fname = sys._getframe(1).f_code.co_name + + print("Warning: %s (%s)" % (msg, fname)) + + +def error(msg): + """Write ``msg`` to error log.""" + cflog.error(" calfem.core: "+msg) + + +def info(msg): + """Write ``msg`` to info log.""" + cflog.info(" calfem.core: "+msg) + + +def spring1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param float ep: spring stiffness or analog quantity (ep = k). + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') + + +def spring1s(ep, ed): + """ + Compute element force in spring element (spring1e). + + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force [N] + """ + k = ep + return k*(ed[1]-ed[0]) + + +def bar1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param ep float: spring stiffness or analog quantity + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') + + +def bar1s(ep, ed): + """ + Compute element force in spring element (spring1e). + + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force + """ + k = ep + return k*(ed[1]-ed[0]) + + +def bar2e(ex, ey, ep): + """ + Compute the element stiffness matrix for two dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: [E, A]: E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [4 x 4] + """ + E = ep[0] + A = ep[1] + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + + Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) + + return G.T*Kle*G + + +def bar2g(ex, ey, ep, N): + """ + Compute element stiffness matrix for two dimensional geometric + nonlinear bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param float N: normal force + :return mat Ke: stiffness matrix [4 x 4] + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [-n[1], n[0], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., -n[1], n[0]] + ]) + + Kle = E*A/L*np.mat([ + [1, 0, -1, 0], + [0, 0, 0, 0], + [-1, 0, 1, 0], + [0, 0, 0, 0] + ])+N/L*np.mat([ + [0, 0, 0, 0], + [0, 1, 0, -1], + [0, 0, 0, 0], + [0, -1, 0, 1] + ]) + + return G.T*Kle*G + + +def bar2s(ex, ey, ep, ed): + """ + Compute normal force in two dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, u2, u3, u4] + :return float N: element foce [N] + """ + E = ep[0] + A = ep[1] + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + + #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) + + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u + return N.item() + + +def bar2gs(ex, ey, ep, ed): + """ + Calculate section forces in a two dimensional geometric + nonlinear bar element (bar2g). + Parameters: + ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E A] element properties; + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector + + Returns: + es = [N1; + N2 ] section forces, local directions + + QX: axial force + + edi = [ u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(es)= n x 1 + ...] + + eci = [ x1 ; local x-coordinates of the evaluation + x2 ; points, (x1=0 and xn=L) + ...] + """ + EA = ep[0]*ep[1] + ne = 2 + + dx = ex[1] - ex[0] + dy = ey[1] - ey[0] + L = np.sqrt(dx**2 + dy**2) + + n = [dx/L, dy/L, -dy/L, dx/L] + G = np.array([ + [n[0], n[1], 0., 0.], + [n[2], n[3], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., n[2], n[3]] + ]) + + edl = G@ed.reshape(-1,1) + a1 = np.array([edl[0], edl[2]]).reshape(-1,1) + + C1 = np.array([[1., 0.,], + [-1/L, 1/L]]) + C1a = C1@a1 + + x = np.linspace(0,L,ne).reshape(-1,1) + zero = np.zeros(x.shape) + one = np.ones(x.shape) + + u = np.concatenate((one, x),axis=1)@C1a + du = np.concatenate((zero, one),axis=1)@C1a + + N = EA*du + return N, N[0].item(), u, x + + +def bar3e(ex, ey, ez, ep): + """ + Compute element stiffness matrix for three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [6 x 6] + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(3) + + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) + + Kle = E*A/L*np.mat([ + [1, -1], + [-1, 1] + ]) + + return G.T*Kle*G + + +def bar3s(ex, ey, ez, ep, ed): + """ + Compute normal force in three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, ..., u6] + :return float N: normal force + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(3) + + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) + + #Kle = E*A/L*np.mat([ + # [ 1,-1], + # [-1, 1] + #]) + + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u + + return N.item() + +def beam1e(ex, ep, eq=None): + """ + Compute the stiffness matrix for a one dimensional beam element. + + :param list ex: element x coordinates [x1, x2] + :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia + :param float eq: distributed load [qy] + :return mat Ke: element stiffness matrix [4 x 4] + :return mat fe: element load vector [4 x 1] (if eq!=None) + """ + L = ex[1]-ex[0] + + E = ep[0] + I = ep[1] + + qy = 0. + if eq: + qy = eq + + Ke = E*I/(L**3) * np.mat([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T + + if eq is None: + return Ke + else: + return Ke, fe + +def beam1s(ex, ep, ed, eq=None, nep=None): + """ + Compute section forces in one dimensional beam element (beam1e). + + Parameters: + + ex = [x1 x2] element node coordinates + + ep = [E I] element properties, + E: Young's modulus + I: moment of inertia + + ed = [u1 ... u4] element displacements + + eq = qy distributed load, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [ V1 M1 section forces, local directions, in + V2 M2 n points along the beam, dim(es)= n x 2 + .........] + + edi = [ v1 element displacements, local directions, + v2 in n points along the beam, dim(es)= n x 1 + .......] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + """ + EI = ep[0]*ep[1] + L = ex[1]-ex[0] + + qy = 0. + + if eq: + qy = eq + + ne = 2 + + if nep != None: + ne = nep + + Cinv = np.mat([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [-3/(L**2), -2/L, 3/(L**2), -1/L], + [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] + ]) + + Ca = (Cinv@ed).T + + x = np.asmatrix(np.linspace(0., L, nep)).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ + + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) + d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ + + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) + d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) + + M = EI*d2v + V = -EI*d3v + edi = v + eci = x + es = np.concatenate((V, M), 1) + + return (es, edi, eci) + + + +def beam2e(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional beam element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia + :param list eq: distributed loads, local directions [qx, qy] + :return mat Ke: element stiffness matrix [6 x 6] + :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) + """ + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) + + E = ep[0] + A = ep[1] + I = ep[2] + + qx = 0. + qy = 0. + if not eq is None: + qx = eq[0] + qy = eq[1] + + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], + [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], + [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] + ]) + + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2s(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E A I] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1 ... u6] element displacements + + eq = [qx qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + .........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .......] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + """ + EA = ep[0]*ep[1] + EI = ep[0]*ep[2] + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) + + qx = 0. + qy = 0. + + if not eq is None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 0., 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*L**2, 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T - + np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) + A = np.matrix([M[0], M[3]]).T + B = np.matrix([M[1], M[2], M[4], M[5]]).T + + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) + du = np.concatenate((one, zero), 1)*A-x*qx/EA + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, + one), 1)*B+np.power(x, 4)*qy/(24*EI) + d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + B+np.power(x, 2)*qy/(2*EI) + d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI + + N = EA*du + M = EI*d2v + V = -EI*d3v + edi = np.concatenate((u, v), 1) + eci = x + es = np.concatenate((N, V, M), 1) + + return (es, edi, eci) + + +def beam2t(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional elastic + Timoshenko beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E G A I ks] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + I: Moment of inertia + ks: Shear correction factor + + eq = [qx qy] distributed loads, local directions + + Returns: + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + + """ + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + E = ep[0] + Gm = ep[1] + A = ep[2] + I = ep[3] + ks = ep[4] + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + m = (12/L**2)*(E*I/(Gm*A*ks)) + + Kle = E/(1+m)*np.mat([ + [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], + [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], + [0., 6*I/L**2., 4*I * + (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], + [-A*(1+m)/L, 0., 0., + A*(1+m)/L, 0., 0.], + [0., -12*I/L**3., -6*I/L**2., + 0., 12*I/L**3., -6*I/L**2.], + [0., 6*I/L**2., 2*I * + (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] + ]) + + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq == None: + return Ke + else: + return Ke, fe + + +def beam2ts(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,G,A,I,ks] element properties, + E: Young's modulus + G: shear modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacements + + eq = [qx, qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [[N1,V1,M1], section forces, local directions, in + [N2,V2,M2], n points along the beam, dim(es)= n x 3 + ..........] + + edi = [[u1,v1,teta1], element displacements, local directions, + [u2,v2,teta2], and rotation of cross section at + .............] in n points along the beam, dim(es)= n x 2 + + (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) + + eci = [[x1], local x-coordinates of the evaluation + [x2], points, (x1=0 and xn=L) + ....] + + """ + EA = ep[0]*ep[2] + EI = ep[0]*ep[3] + GAK = ep[1]*ep[2]*ep[4] + alfa = EI/GAK + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 6*alfa, 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( + 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) + C2 = np.mat([M[0], M[3]]).T + C4 = np.mat([M[1], M[2], M[4], M[5]]).T + + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) + du = np.concatenate((one, zero), 1)*C2-qx*x/EA + + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ + C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) + dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), + 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + + teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), + 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) + dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + C4+qy*np.power(x, 2)/(2*EI) + + N = EA*du + M = EI*dteta + V = GAK*(dv-teta) + + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v, teta), 1) + eci = x + + if nep != None: + return es, edi, eci + else: + return es + + +def beam2w(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional beam element + on elastic foundation. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness + + eq = [qx, qy] distributed loads, local directions + + Returns: + + Ke beam stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + """ + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2) + + E, A, I, ka, kt = ep + + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq + + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) + + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq != None: + return Ke, fe + else: + return Ke + + +def beam2ws(ex, ey, ep, ed, eq=None): + """ + Compute section forces in a two dimensional beam element + on elastic foundation. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness + + ed = [u1, ... ,u6] element displacement vector + + eq = [qx, qy] distributed loads, local directions + + Returns: + + es = [[N1, V1, M1], + [N2, V2, M2]] element forces, local direction + """ + if np.asmatrix(ed).shape[0] > 1: + error("Only one row is allowed in the ed matrix !!!") + return + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I, ka, kt = ep + + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq + + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) + + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + P = Kle*G*np.asmatrix(ed).T-fle + + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) + + return es + + +def beam2g(ex, ey, ep, N, eq=None): + """ + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + N axial force in the beam + + eq distributed transverse load + + Returns: + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + """ + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + q = eq[0] + else: + q = 0 + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I = ep + + rho = -N*L**2/(np.pi**2*E*I) + + kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps + + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 + + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., + 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 4*E*I*f3/L, + 0., -6*E*I*f2/L**2., 2*E*I*f4/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., + 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 2*E*I*f4/L, + 0., -6*E*I*f2/L**2., 4*E*I*f3/L] + ]) + + fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq != None: + return Ke, fe + else: + return Ke + + +def beam2gs(ex, ey, ep, ed, N, eq=None): + """ + Calculate section forces in a two dimensional nonlinear + beam element. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacement vector + + N axial force + + eq = [qy] distributed transverse load + + Returns: + + es = [[N1,V1,M1], element forces, local directions + [N2,V2,M2]] + """ + if eq != None: + eq = eq[0] + else: + eq = 0 + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I = ep + + rho = -N*L**2/(np.pi**2*E*I) + + eps = 2.2204e-16 + kL = np.pi*np.sqrt(abs(rho))+eps + + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 + + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, + 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, + 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] + ]) + + fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + u = np.asmatrix(ed).T + P = Kle*G*u-fle + + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) + + return es + + +def beam2d(ex, ey, ep): + """ + Calculate the stiffness matrix Ke, the mass matrix Me + and the damping matrix Ce for a 2D elastic Bernoulli + beam element. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe + + Returns: + + Ke element stiffness matrix (6 x 6) + Me element mass martix + Ce element damping matrix, optional + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep + + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + Mle = m*L/420*np.mat([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] + ]) + + Cle = a*Mle+b*Kle + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + Me = G.T*Mle*G + Ce = G.T*Cle*G + + if np.size(ep) == 4: + return Ke, Me + elif np.size(ep) == 6: + return Ke, Me, Ce + + +def beam3e(ex, ey, ez, eo, ep, eq=None): + """ + Calculate the stiffness matrix for a 3D elastic Bernoulli + beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] + ez = [z1 z2] element node coordinates + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + eq = [qx qy qz qw] distributed loads + + Returns: + + Ke beam stiffness matrix (12 x 12) + + fe equivalent nodal forces (12 x 1) + + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) + + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) + + E, Gs, A, Iy, Iz, Kv = ep + + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq + + a = E*A/L + b = 12*E*Iz/L**3 + c = 6*E*Iz/L**2 + d = 12*E*Iy/L**3 + e = 6*E*Iy/L**2 + f = Gs*Kv/L + g = 2*E*Iy/L + h = 2*E*Iz/L + + Kle = np.mat([ + [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], + [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], + [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], + [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], + [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], + [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], + [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], + [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], + [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], + [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], + [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], + [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] + ]) + + fle = L/2*np.mat([qx, qy, qz, qw, -qz*L/6, qy*L/6, + qx, qy, qz, qw, qz*L/6, -qy*L/6]).T + + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + + #An = np.append([n1,n2],[n3],0) + + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq == None: + return Ke + else: + return Ke, fe + + +def beam3s(ex, ey, ez, eo, ep, ed, eq=None, n=None): + """ + Calculate the variation of the section forces and displacements + along a three-dimensional beam element. + + Parameters: + + ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + ed the element displacement vector from the + global coordinate system + + eq = [qx qy qz qw] the disibuted axial, transversal and + torsional loads + + n the number of point in which displacements + and section forces are to be computed + + Returns: + + es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along + [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis + [..,...,...,..,...,...], + [Nn,Vyn,Vzn,Tn,Myn,Mzn]] + + edi = [[u1,v1,w1,fi1], displacements in n points along + [u2,v2,w2,fi2], the local x-axis + [..,..,..,...], + [un,vn,wn,fin]] + + eci = [[x1], local x-coordinates of the evaluation + [x2], points + [..], + [xn]] + + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) + + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) + + EA = ep[0]*ep[2] + EIy = ep[0]*ep[3] + EIz = ep[0]*ep[4] + GKv = ep[1]*ep[5] + + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq + + ne = 2 + if n != None: + ne = n + + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, + 0, 0, 0, n3[0], n3[1], n3[2]] + ]) + + u = G*np.asmatrix(ed).T-np.array([ # u is the local element displacement + [0], # vector minus the particular solution + [0], # to the beam's diff.eq:s + [0], + [0], + [0], + [0], + [-qx*L**2/(2*EA)], + [qy*L**4/(24*EIz)], + [qz*L**4/(24*EIy)], + [-qw*L**2/(2*GKv)], + [-qz*L**3/(6*EIy)], + [qy*L**3/(6*EIz)] + ]) + + C = np.mat([ + [0, 1, 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, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [L, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], + [0, 0, L**3, L**2, L, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, L**3, L**2, L, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L, 1], + [0, 0, 0, 0, 0, 0, -3*L**2, -2*L, -1, 0, 0, 0], + [0, 0, 3*L**2, 2*L, 1, 0, 0, 0, 0, 0, 0, 0], + ]) + + m = np.linalg.inv(C)*u + eci = np.zeros((ne, 1)) + es = np.zeros((ne, 6)) + edi = np.zeros((ne, 4)) + for i in np.arange(ne): + x = i*L/(ne-1) + eci[i, 0] = x + es[i, :] = (np.mat([ + [EA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, -6*EIz, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, -6*EIy, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GKv, 0], + [0, 0, 0, 0, 0, 0, -6*EIy*x, -2*EIy, 0, 0, 0, 0], + [0, 0, 6*EIz*x, 2*EIz, 0, 0, 0, 0, 0, 0, 0, 0] + ])*m+np.array([-qx*x, -qy*x, -qz*x, -qw*x, -qz*x**2/2, qy*x**2/2]).reshape(6, 1)).T + + edi[i, :] = (np.mat([ + [x, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, x**3, x**2, x, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, x**3, x**2, x, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x, 1] + ])*m+np.array([-qx*x**2/(2*EA), qy*x**4/(24*EIz), qz*x**4/(24*EIy), -qw*x**2/(2*GKv)]).reshape(4, 1)).T + + if n == None: + return es + else: + return es, edi, eci + + +def flw2te(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + ep = [t] element thickness + + D = [kxx kxy; + kyx kyy] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (3 x 3) + + fe element load vector (3 x 1) + + """ + t = ep[0] + if eq == None: + eq = 0. + + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + A = 0.5*np.linalg.det(C) + + Ke = B.T*D*B*t*A + fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 + + if eq == 0.: + return Ke + else: + return Ke, fe + + +def flw2ts(ex, ey, D, ed): + """ + Compute flows or corresponding quantities in the triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + D = [kxx kxy + kyx kyy] constitutive matrix + + ed =[u1 u2 u3] u1,u2,u3: nodal values + .. .. ..; + + Returns: + + es=[ qx qy ] + ... ..] element flows + + et=[ gx gy ] + ... ..] element gradients + + """ + + if len(ex.shape) > 1: + qs = np.zeros([ex.shape[0], 2]) + qt = np.zeros([ex.shape[0], 2]) + row = 0 + for exr, eyr, edr in zip(ex, ey, ed): + exm = np.asmatrix(exr) + eym = np.asmatrix(eyr) + edm = np.asmatrix(edr) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + + qs[row, :] = (-D*B*edm.T).T + qt[row, :] = (B*edm.T).T + row += 1 + + return qs, qt + else: + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + edm = np.asmatrix(ed) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + + qs = -D*B*edm.T + qt = B*edm.T + + return qs.T, qt.T + + +def flw2qe(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (4 x 4) + + fe element load vector (4 x 1) + + """ + xc = sum(ex)/4. + yc = sum(ey)/4. + + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) + + if eq == None: + k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) + K = assem(np.array([1, 2, 5]), K, k1) + k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) + K = assem(np.array([2, 3, 5]), K, k1) + k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) + K = assem(np.array([3, 4, 5]), K, k1) + k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) + K = assem(np.array([4, 1, 5]), K, k1) + else: + k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) + K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) + K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) + K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) + K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) + Ke1, fe1 = statcon(K, f, np.array([5])) + + Ke = Ke1 + fe = fe1 + + if eq == None: + return Ke + else: + return Ke, fe + + +def flw2qs(ex, ey, ep, D, ed, eq=None): + """ + Compute flows or corresponding quantities in the + quadrilateral field element. + + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + ed = [[u1, u2, u3, u4], + [.., .., .., ..]] u1,u2,u3,u4: nodal values + + eq heat supply per unit volume + + Returns: + + es = [[qx, qy], + [.., ..]] element flows + + et = [[gx, gy], + [.., ..]] element gradients + + """ + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) + + xm = sum(ex)/4 + ym = sum(ey)/4 + + if eq == None: + q = 0 + else: + q = eq + + En = np.array([ + [1, 2, 5], + [2, 3, 5], + [3, 4, 5], + [4, 1, 5] + ]) + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) + + if eq == None: + k1 = flw2te(ex1, ey1, ep, D) + K = assem(En[0], K, k1) + k1 = flw2te(ex2, ey2, ep, D) + K = assem(En[1], K, k1) + k1 = flw2te(ex3, ey3, ep, D) + K = assem(En[2], K, k1) + k1 = flw2te(ex4, ey4, ep, D) + K = assem(En[3], K, k1) + else: + k1, f1 = flw2te(ex1, ey1, ep, D, q) + K, f = assem(En[0], K, k1, f, f1) + k1, f1 = flw2te(ex2, ey2, ep, D, q) + K, f = assem(En[1], K, k1, f, f1) + k1, f1 = flw2te(ex3, ey3, ep, D, q) + K, f = assem(En[2], K, k1, f, f1) + k1, f1 = flw2te(ex4, ey4, ep, D, q) + K, f = assem(En[3], K, k1, f, f1) + + if ed.ndim == 1: + ed = np.array([ed]) + + ni, nj = np.shape(ed) + + a = np.zeros((5, ni)) + for i in range(ni): + a[np.ix_(range(5), [i])], r = np.asarray( + solveq(K, f, np.arange(1, 5), ed[i])) + + s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) + s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) + s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) + s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) + + es = (s1+s2+s3+s4)/4. + et = (t1+t2+t3+t4)/4. + + return es, et + + +def flw2i4e(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 4 node isoparametric field element + + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [t ir] thickness and integration rule + + D = [[kxx kxy], + [kyx kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + Ke element 'stiffness' matrix (4 x 4) + fe element load vector (4 x 1) + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + + Ke1 = np.mat(np.zeros((4, 4))) + fe1 = np.mat(np.zeros((4, 1))) + JT = dNr*np.mat([ex, ey]).T + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq == None: + return Ke1*t + else: + return Ke1*t, fe1*t*eq + + +def flw2i4s(ex, ey, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 4 node isoparametric element. + + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [t ir] thickness and integration rule + + D = [[kxx kxy], + [kyx kyy]] constitutive matrix + + ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values + + Returns: + es = [[qx, qy], + [.., ..]] element flows + + et = [[qx, qy], + [... ..]] element gradients + + eci=[[ix1, iy1], Gauss point location vector + [... ...], nint: number of integration points + [ix(nint), iy(nint)] + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T + + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinatn == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw2i8e(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1, ..., x8] element coordinates + ey = [y1, ..., y8] + + ep = [t, ir] thickness and integration rule + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq != None: + return Ke1*t, fe1*t*q + else: + return Ke1*t + + +def flw2i8s(ex, ey, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 8 node isoparametric element. + + Parameters: + + ex = [x1,x2,x3....,x8] element coordinates + ey = [y1,y2,y3....,y8] + + ep = [t,ir] thickness and integration rule + + D = [[kxx,kxy], + [kyx,kyy]] constitutive matrix + + ed = [u1,....,u8] u1,....,u8: nodal values + + Returns: + es = [[qx,qy], + [..,..]] element flows + + et = [[qx,qy], + [..,..]] element gradients + + eci=[[ix1,iy1], Gauss point location vector + [...,...], nint: number of integration points + [ix(nint),iy(nint)]] + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T + + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw3i8e(ex, ey, ez, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] + + ep = [ir] Ir: Integration rule + + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix + + eq heat supply per unit volume + + Output: + + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) + + """ + ir = ep[0] + ngp = ir*ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + else: + info("Used number of integration points not implemented") + return + + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. + + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey, ez]).T + + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq != None: + return Ke1, fe1*q + else: + return Ke1 + + +def flw3i8s(ex, ey, ez, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 8 node (3-dim) isoparametric field element. + + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] + + ep = [ir] Ir: Integration rule + + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix + + ed = [[u1,....,u8], element nodal values + [..,....,..]] + + Output: + + es = [[qx,qy,qz], + [..,..,..]] element flows(s) + + et = [[qx,qy,qz], element gradients(s) + [..,..,..]] + + eci = [[ix1,ix1,iz1], location vector + [...,...,...], nint: number of integration points + [ix(nint),iy(nint),iz(nint)]] + + """ + ir = ep[0] + ngp = ir*ir*ir + + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + else: + info("Used number of integration points not implemented") + return + + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. + + eci = N*np.mat([ex, ey, ez]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey, ez]).T + + es = np.mat(np.zeros((ngp*red, 3))) + et = np.mat(np.zeros((ngp*red, 3))) + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def plante(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a triangular plane stress or plane strain element. + + Parameters: + + ex = [x1,x2,x3] element coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + D constitutive matrix + + eq = [[bx], bx: body force x-dir + [by]] by: body force y-dir + + Returns: + + Ke element stiffness matrix (6 x 6) + fe equivalent nodal forces (6 x 1) (if eq is given) + + """ + + ptype, t = ep + + bx = 0.0 + by = 0.0 + + if not eq is None: + bx = eq[0] + by = eq[1] + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + # --------- plane stress -------------------------------------- + + if ptype == 1: + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + colD = D.shape[1] + + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D + + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + + if eq is None: + return Ke + else: + return Ke, fe.T + + #--------- plane strain -------------------------------------- + + elif ptype == 2: + B = np.mat([ + [0, 1, 0, 0, 0, 0, ], + [0, 0, 0, 0, 0, 1, ], + [0, 0, 1, 0, 1, 0, ] + ])*np.linalg.inv(C) + + colD = D.shape[1] + + if colD > 3: + Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] + else: + Dm = D + + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + + if eq == None: + return Ke + else: + return Ke, fe.T + + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + if eq == None: + return None + else: + return None, None + + +def plants(ex, ey, ep, D, ed): + """ + Calculate element normal and shear stress for a + triangular plane stress or plane strain element. + + INPUT: ex = [x1 x2 x3] element coordinates + ey = [y1 y2 y3] + + ep = [ptype t ] ptype: analysis type + t: thickness + + D constitutive matrix + + ed =[u1 u2 ...u6 element displacement vector + ...... ] one row for each element + + OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix + ...... ] one row for each element + + et = [ epsx epsy [epsz] gamxy element strain matrix + ...... ] one row for each element + """ + + ptype = ep[0] + + if np.ndim(ex) == 1: + ex = np.array([ex]) + if np.ndim(ey) == 1: + ey = np.array([ey]) + if np.ndim(ed) == 1: + ed = np.array([ed]) + + rowed = ed.shape[0] + rowex = ex.shape[0] + + # --------- plane stress -------------------------------------- + + if ptype == 1: + + colD = D.shape[1] + + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D + + incie = 0 + + if rowex == 1: + incie = 0 + else: + incie = 1 + + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) + + ie = 0 + + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) + + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + + ee = B*np.asmatrix(ed[ie, :]).T + + if colD > 3: + ss = np.zeros([colD, 1]) + ss[[0, 1, 3]] = Dm*ee + ee = Cm*ss + else: + ss = Dm*ee + + et[ie, :] = ee.T + es[ie, :] = ss.T + + ie = ie + incie + + return es, et + + # --------- plane strain -------------------------------------- + elif ptype == 2: # Implementation by LAPM + colD = D.shape[1] + incie = 0 + + if rowex == 1: + incie = 0 + else: + incie = 1 + + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) + + ie = 0 + + ee = np.zeros([colD, 1]) + + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) + + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + + e = B*np.asmatrix(ed[ie, :]).T + + if colD > 3: + ee[[0, 1, 3]] = e + else: + ee = e + + et[ie, :] = ee.T + es[ie, :] = (D*ee).T + + ie = ie + incie + + return es, et + + else: + print("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def plantf(ex, ey, ep, es): + """ + Compute internal element force vector in a triangular element + in plane stress or plane strain. + + Parameters: + + ex = [x1,x2,x3] node coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + OUTPUT: + + fe = [[f1],[f2],...,[f8]] internal force vector + + """ + + ptype, t = ep + + colD = es.shape[1] + + #--------- plane stress -------------------------------------- + + if ptype == 1: + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((0, 1, 3))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + #--------- plane strain -------------------------------------- + + elif ptype == 2: + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def platre(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a rectangular plate element. + NOTE! Element sides must be parallel to the coordinate axis. + + Parameters: + + ex = [x1,x2,x3,x4] element coordinates + ey = [y1,y2,y3,y4] + + ep = [t] thicknes + + D constitutive matrix for + plane stress + + eq = [qz] load/unit area + Returns: + + Ke element stiffness matrix (12 x 12) + fe equivalent nodal forces (12 x 1) + + """ + Lx = (ex[2]-ex[0]).astype(float) + Ly = (ey[2]-ey[0]).astype(float) + t = ep[0] + + D = t**3/12.*D + + A1 = Ly/(Lx**3) + A2 = Lx/(Ly**3) + A3 = 1/Lx/Ly + A4 = Ly/(Lx**2) + A5 = Lx/(Ly**2) + A6 = 1/Lx + A7 = 1/Ly + A8 = Ly/Lx + A9 = Lx/Ly + + C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] + C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + + C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] + C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] + C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] + C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] + C11 = A5*D[1, 1]-0.4*A6*D[2, 2] + C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + + C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] + C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] + C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] + C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] + C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] + C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] + C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] + C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] + C21 = D[0, 1] + + Keq = np.mat(np.zeros((12, 12))) + Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 + Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 + Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 + Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 + Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 + Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 + Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 + Keq[7, 7:13] = C13, -C21, -C9, C15, 0 + Keq[8, 8:13] = C14, -C8, 0, C18 + Keq[9, 9:13] = C1, -C5, -C6 + Keq[10, 10:13] = C13, C21 + Keq[11, 11] = C14 + Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + + if eq != None: + q = eq + R1 = q*Lx*Ly/4 + R2 = q*Lx*Ly**2/24 + R3 = q*Ly*Lx**2/24 + + feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + + if eq != None: + return Keq, feq + else: + return Keq + + +def planqe(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex=[x1 x2 x3 x4] element coordinates + ey=[y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: element thickness + + D constitutive matrix + + eq = [bx; bx: body force in x direction + by] by: body force in y direction + + OUTPUT: Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (row array) + """ + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), + np.array([ey[0], ey[1], ym]), ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), + np.array([ey[1], ey[2], ym]), ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), + np.array([ey[2], ey[3], ym]), ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), + np.array([ey[3], ey[0], ym]), ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + Ke, fe = statcon(K, f, np.array([[9], [10]])) + + if eq == None: + return Ke + else: + return Ke, fe + + +def planqs(ex, ey, ep, D, ed, eq=None): + """ + Calculate element normal and shear stress for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: thickness + + D constitutive matrix + + ed = [u1 u2 ..u8] element displacement vector + + eq = [[bx] bx: body force in x direction + [by]] by: body force in y direction + + OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array + et = [ epsx epsy (epsz) gamxy] element strain array + """ + + if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): + raise ValueError( + 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') + + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) + + ke1, fe1 = plante(ex1, ey1, ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex2, ey2, ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex3, ey3, ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex4, ey4, ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + + A1 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) + A2 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) + A3 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) + A4 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) + Atot = A1+A2+A3+A4 + + a, _ = solveq(K, f, np.array(range(1, 9)), ed) + +# ni = ed.shape[0] +# a = np.mat(empty((10,ni))) +# for i in range(ni): +# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] +# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) + + s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) + s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) + s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) + s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) + + es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot + et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot + + # [0] because these are 1-by-3 arrays and we want row arrays out. + return es[0], et[0] + + +def plani4e(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a 4 node isoparametric + element in plane strain or plane stress. + + Parameters: + ex = [x1 ... x4] element coordinates. Row array + ey = [y1 ... y4] + + ep =[ptype, t, ir] ptype: analysis type + t : thickness + ir: integration rule + + D constitutive matrix + + eq = [bx; by] bx: body force in x direction + by: body force in y direction + Any array with 2 elements acceptable + + Returns: + Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (8 x 1) + """ + ptype = ep[0] + t = ep[1] + ir = ep[2] + ngp = ir*ir + if eq == None: + q = np.zeros((2, 1)) + else: + q = np.reshape(eq, (2, 1)) +#--------- gauss points -------------------------------------- + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1]]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1]]) + else: + info("Used number of integrat ion points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + # Shape Functions + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + +# + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T + # --------- plane stress -------------------------------------- + if ptype == 1: + colD = np.shape(D)[0] + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t + fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t + + return Ke1, fe1 +#--------- plane strain -------------------------------------- + elif ptype == 2: + # + colD = np.shape(D)[0] + if colD > 3: + Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + # + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] +# + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t + fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t + return Ke1, fe1 + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + + +def soli8e(ex, ey, ez, ep, D, eqp=None): + """ + Ke=soli8e(ex,ey,ez,ep,D) + [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix for a 8 node (brick) + isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [ir] ir integration rule + + D constitutive matrix + + eq = [bx; by; bz] bx: body force in x direction + by: body force in y direction + bz: body force in z direction + + OUTPUT: Ke : element stiffness matrix + fe : equivalent nodal forces + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-01-24 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + ir = ep[0] + ngp = ir*ir*ir + + if eqp == None: + eq = np.zeros((3, 1)) + else: + eq = eqp + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 + + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) + + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) + + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + + wp = w[:, 0]*w[:, 1]*w[:, 2] + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) + + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + + dNr = dNr/8.0 + + Ke = np.zeros((24, 24)) + fe = np.zeros((24, 1)) + + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) + + JT = dNr@np.concatenate((ex, ey, ez), axis=1) + + eps = np.finfo(float).eps + + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] + + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) + + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] + + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + + Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] + fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] + + if eqp != None: + return Ke, fe + else: + return Ke + + +def soli8s(ex, ey, ez, ep, D, ed): + """ + [es,et]=soli8s(ex,ey,ez,ep,D,ed) + ------------------------------------------------------------- + PURPOSE + Calculate element normal and shear stress for a + 8 node (brick) isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [Ir] Ir: integration rule + + D constitutive matrix + + ed = [u1 u2 ..u24] element displacement vector + + OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; + ...... ... ] + element stress matrix, one row for each + integration point + + es = [ eps epsy epsz epsxy epsyz epsxz ; + ...... ... ] + element strain matrix, one row for each + integration point + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-02-23 (Python version) + + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + + ir = ep[0] + ngp = ir*ir*ir + + ir = ep[0] + ngp = ir*ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 + + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) + + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) + + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + + wp = w[:, 0]*w[:, 1]*w[:, 2] + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) + + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + + dNr = dNr/8.0 + + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) + + JT = dNr@np.concatenate((ex, ey, ez), axis=1) + + eps = np.finfo(float).eps + + eci = N@np.concatenate((ex, ey, ez), axis=1) + et = np.zeros((ngp, 6)) + es = np.zeros((ngp, 6)) + + ed = ed.reshape(1, 24) + + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] + + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) + + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] + + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + + # [6x24] x [24,1] + ee = B@np.transpose(ed) + + et[i, :] = ee.reshape(6,) + es[i, :] = (D@ee).reshape(6,) + + return et, es, eci + + +def assem(edof, K, Ke, f=None, fe=None): + """ + Assemble element matrices Ke ( and fe ) into the global + stiffness matrix K ( and the global force vector f ) + according to the topology matrix edof. + + Parameters: + + edof dof topology array + K the global stiffness matrix + Ke element stiffness matrix + f the global force vector + fe element force vector + + Output parameters: + + K the new global stiffness matrix + f the new global force vector + fe element force vector + + """ + + if edof.ndim == 1: + idx = edof-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + else: + for row in edof: + idx = row-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + + if f is None: + return K + else: + return K, f + + +def solveq(K, f, bcPrescr, bcVal=None): + """ + Solve static FE-equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + + """ + + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] + + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') + + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) + + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] + + fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ + np.asmatrix(bcVal).reshape(nPdofs, 1) + asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) + + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) + a[np.ix_(bcDofs)] = asys + + Q = K*np.asmatrix(a)-f + + return (np.asmatrix(a), Q) + + +def spsolveq(K, f, bcPrescr, bcVal=None): + """ + Solve static FE-equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + + """ + + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] + + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') + + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) + + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] + + bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) + + info("Preparing system matrix...") + + mask = np.ones(K.shape[0], dtype=bool) + mask[bcDofs] = False + + info("step 1... converting K->CSR") + Kcsr = K.asformat("csr") + info("step 2... Kt") + #Kt1 = K[bcDofs] + #Kt = Kt1[:,bcPrescr] + Kt = K[np.ix_((bcDofs), (bcPrescr-1))] + info("step 3... fsys") + fsys = f[bcDofs]-Kt*bcVal_m + info("step 4... Ksys") + Ksys1 = Kcsr[bcDofs] + Ksys = Ksys1[:, bcDofs] + #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] + info("done...") + + info("Solving system...") + asys = dsolve.spsolve(Ksys, fsys) + + info("Reconstructing full a...") + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = bcVal_m + a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() + + a_m = np.asmatrix(a) + Q = K*a_m-f + info("done...") + return (a_m, Q) + + +def eigen(K,M,b=None): + """ + Solve the generalized eigenvalue problem + |K-LM|X = 0, considering boundary conditions + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + M global mass matrix, dim(M) = ndof x ndof + b boundary condition vector, dim(b) = nbc x 1 + + Returns: + + L eigenvalue vector, dim(L) = (ndof-nbc) x 1 + X eigenvectors, dim(X) = ndof x (ndof-nbc) + """ + nd, _ = K.shape + if b is not None: + fdof = np.setdiff1d(np.arange(nd), b-1) + D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) + D = np.real(D) + nfdof, _ = X1.shape + for j in range(nfdof): + mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X2 = np.zeros(X1.shape) + for ind,j in enumerate(s_order): + X2[:,ind] = X1[:,j] + X = np.zeros((nd,nfdof)) + X[fdof,:] = X2 + return L, X + else: + D, X1 = eig(K, M) + D = np.real(D) + for j in range(nd): + mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X = np.copy(X1) + for ind,j in enumerate(s_order): + X[:,ind] = X1[:,j] + return L, X + + +def gfunc(G,dt): + """ + Form vector with function values at equally spaced + points by linear interpolation + + Parameters: + + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step + + Returns: + + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 + + +def step1(K,C,f,a0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. + + Parameters: + + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta are: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + if not np.array(C).any(): + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + +def extract_eldisp(edof, a): + """ + Extract element displacements from the global displacement + vector according to the topology matrix edof. + + Parameters: + + a the global displacement vector + edof dof topology array + + Returns: + + ed: element displacement array + + """ + + ed = None + + if edof.ndim == 1: + nDofs = len(edof) + ed = np.zeros([nDofs]) + idx = edof-1 + ed[:] = a[np.ix_(idx)].T + else: + nElements = edof.shape[0] + nDofs = edof.shape[1] + ed = np.zeros([nElements, nDofs]) + i = 0 + for row in edof: + idx = row-1 + ed[i, :] = a[np.ix_(idx)].T + i += 1 + + return ed + + +extractEldisp = extract_eldisp +extract_ed = extract_eldisp + + +def statcon(K, f, cd): + """ + Condensation of static FE-equations according to the vector cd. + + Parameters: + + K global stiffness matrix, dim(K) = nd x nd + f global load vector, dim(f)= nd x 1 + + cd vector containing dof's to be eliminated + dim(cd)= nc x 1, nc: number of condensed dof's + Returns: + + K1 condensed stiffness matrix, + dim(K1)= (nd-nc) x (nd-nc) + f1 condensed load vector, dim(f1)= (nd-nc) x 1 + """ + nd, nd = np.shape(K) + cd = (cd-1).flatten() + + aindx = np.arange(nd) + aindx = np.delete(aindx, cd, 0) + bindx = cd + + Kaa = np.mat(K[np.ix_(aindx, aindx)]) + Kab = np.mat(K[np.ix_(aindx, bindx)]) + Kbb = np.mat(K[np.ix_(bindx, bindx)]) + + fa = np.mat(f[aindx]) + fb = np.mat(f[bindx]) + + K1 = Kaa-Kab*Kbb.I*Kab.T + f1 = fa-Kab*Kbb.I*fb + + return K1, f1 + + +def c_mul(a, b): + return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) + + +def dofHash(dof): + if len(dof) == 1: + return dof[0] + value = 0x345678 + for item in dof: + value = c_mul(1000003, value) ^ hash(item) + value = value ^ len(dof) + if value == -1: + value = -2 + return value + + +def create_dofs(nCoords, nDof): + """ + Create dof array [nCoords x nDof] + """ + return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 + + +createdofs = create_dofs + + +def coordxtr(edof, coords, dofs, nen=-1): + """ + Create element coordinate matrices ex, ey, ez from edof + coord and dofs matrices. + + Parameters: + + edof [nel x (nen * nnd)], nnd = number of node dofs + coords [ncoords x ndims], ndims = node dimensions + dofs [ncoords x nnd] + + Returns: + + ex if ndims = 1 + ex, ey if ndims = 2 + ex, ey, ez if ndims = 3 + """ + + # Create dictionary with dof indices + + dofDict = {} + nDofs = np.size(dofs, 1) + nElements = np.size(edof, 0) + n_element_dofs = np.size(edof, 1) + nDimensions = np.size(coords, 1) + nElementDofs = np.size(edof, 1) + + if nen == -1: + nElementNodes = int(nElementDofs/nDofs) + else: + nElementNodes = nen + + if nElementNodes*nDofs != n_element_dofs: + nDofs = nElementNodes*nDofs - n_element_dofs + user_warning( + "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) + + idx = 0 + for dof in dofs: + #dofDict[dofHash(dof)] = idx + dofDict[hash(tuple(dof[0:nDofs]))] = idx + idx += 1 + + # Loop over edof and extract element coords + + ex = np.zeros((nElements, nElementNodes)) + ey = np.zeros((nElements, nElementNodes)) + ez = np.zeros((nElements, nElementNodes)) + + elementIdx = 0 + for etopo in edof: + for i in range(nElementNodes): + i0 = i*nDofs + i1 = i*nDofs+nDofs-1 + dof = [] + if i0 == i1: + dof = [etopo[i*nDofs]] + else: + dof = etopo[i*nDofs:(i*nDofs+nDofs)] + + nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] + + if nDimensions >= 1: + ex[elementIdx, i] = nodeCoord[0] + if nDimensions >= 2: + ey[elementIdx, i] = nodeCoord[1] + if nDimensions >= 3: + ez[elementIdx, i] = nodeCoord[2] + + elementIdx += 1 + + if nDimensions == 1: + return ex + + if nDimensions == 2: + return ex, ey + + if nDimensions == 3: + return ex, ey, ez + + +coord_extract = coordxtr + + +def hooke(ptype, E, v): + """ + Calculate the material matrix for a linear + elastic and isotropic material. + + Parameters: + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + E Young's modulus + v Poissons const. + + Returns: + + D material matrix + + """ + + if ptype == 1: + D = E*np.matrix( + [[1, v, 0], + [v, 1, 0], + [0, 0, (1-v)/2]] + )/(1-v**2) + elif ptype == 2: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 3: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 4: + D = E*np.matrix( + [[1-v, v, v, 0, 0, 0], + [v, 1-v, v, 0, 0, 0], + [v, v, 1-v, 0, 0, 0], + [0, 0, 0, (1-2*v)/2, 0, 0], + [0, 0, 0, 0, (1-2*v)/2, 0], + [0, 0, 0, 0, 0, (1-2*v)/2]] + )/(1+v)/(1-2*v) + else: + info("ptype not supported.") + + return D + + +def effmises(es, ptype): + """ + Calculate effective von mises stresses. + + Parameters: + + es + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + Returns: + + eseff = [eseff_0 .. eseff_nel-1] + + """ + + nel = np.size(es, 0) + escomps = np.size(es, 1) + + eseff = np.zeros([nel]) + + if ptype == 1: + sigxx = es[:, 0] + sigyy = es[:, 1] + sigxy = es[:, 2] + eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) + return eseff + + +def stress2nodal(eseff, edof): + """ + Convert element effective stresses to nodal effective + stresses. + + Parameters: + + eseff = [eseff_0 .. eseff_nel-1] + edof = [dof topology array] + + Returns: + + ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] + .. + ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] + + """ + + values = np.zeros(edof.max()) + elnodes = int(np.size(edof, 1) / 2) + + for etopo, eleseff in zip(edof, eseff): + values[etopo-1] = values[etopo-1] + eleseff / elnodes + + evtemp = extractEldisp(edof, values) + ev = evtemp[:, range(0, elnodes*2, 2)] + + return ev + + +def beam2crd_old(ex, ey, ed, mag): + """ + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- + + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + J Lindemann 2021-12-30 (Python) + + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + nie, ned = ed.shape + + excd = np.zeros([nie, 20]) + eycd = np.zeros([nie, 20]) + + for i in range(nie): + + b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) + L = np.asscalar(np.sqrt(b@np.transpose(b))) + n = b/L + + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + d = ed[i, :] + dl = G @ d + + xl = np.linspace(0.0, L, 20) + one = np.ones(xl.shape) + + Cis = np.array([ + [-1.0, 1.0], + [L, 0.0] + ]) / L + + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + + xl_one = np.transpose(np.vstack((xl, one))) + + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + + Cib = np.array([ + [12, 6*L, -12, 6*L], + [-6*L, -4*L**2, 6*L, -2*L**2], + [0, L**3, 0, 0], + [L**3, 0, 0, 0] + ])/L**3 + + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld + + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] + + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, 20) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) + + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] + + return excd, eycd + + +def beam2crd(ex=None, ey=None, ed=None, mag=None): + """ + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- + + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + + nie, ned = ed.shape + + n_coords = 21 + + excd = np.zeros([nie, n_coords]) + eycd = np.zeros([nie, n_coords]) + + for i in range(nie): + b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) + L = np.sqrt(b @ np.transpose(b)) + n = b / L + + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, - n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + d = np.transpose(ed[i, :]) + dl = G @ d + xl = np.transpose(np.linspace(0, L, n_coords)) + one = np.ones(xl.shape) + + Cis = np.array([ + [-1, 1], + [L, 0] + ]) / L + + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + xl_one = np.transpose(np.vstack((xl, one))) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + + Cib = np.array([ + [12, 6 * L, - 12, 6 * L], + [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], + [0, L ** 3, 0, 0], + [L ** 3, 0, 0, 0] + ]) / L ** 3 + + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld + + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] + + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, n_coords) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] + )@one.reshape(1, n_coords) + + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] + + return excd, eycd \ No newline at end of file diff --git a/calfem/editor.py b/calfem/editor.py index 4b270e5..7bf4ab5 100644 --- a/calfem/editor.py +++ b/calfem/editor.py @@ -20,6 +20,7 @@ import calfem.geometry as cfg import calfem.vis_mpl as cfv import calfem.editor_scene as editor_scene +import calfem.editor_ui as editor_ui app = None @@ -31,8 +32,11 @@ def __init__(self): super(QMainWindow, self).__init__() self.app = app - root = os.path.dirname(os.path.realpath(__file__)) - loadUi(os.path.join(root, 'editor.ui'), self) + #root = os.path.dirname(os.path.realpath(__file__)) + #loadUi(os.path.join(root, 'editor.ui'), self) + + ui = editor_ui.Ui_MainWindow() + ui.setupUi(self) # loadUi('editor.ui', self) loadUI kan ladd ui-fil och lägga till objekt direkt i klassen. self.setWindowTitle("CALFEM Geometry Editor") diff --git a/calfem/editor_ui.py b/calfem/editor_ui.py new file mode 100644 index 0000000..a8293bc --- /dev/null +++ b/calfem/editor_ui.py @@ -0,0 +1,1208 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'editor.ui' +# +# Created by: PyQt5 UI code generator 5.9.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1493, 785) + MainWindow.setStyleSheet("") + MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.centralwidget = QtWidgets.QWidget(MainWindow) + MainWindow.centralwidget.setStyleSheet("QWidget{\n" +"background: rgb(220, 220, 220);\n" +"}") + MainWindow.centralwidget.setObjectName("centralwidget") + MainWindow.verticalLayout_2 = QtWidgets.QVBoxLayout(MainWindow.centralwidget) + MainWindow.verticalLayout_2.setObjectName("verticalLayout_2") + MainWindow.tabWidget = QtWidgets.QTabWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.tabWidget.sizePolicy().hasHeightForWidth()) + MainWindow.tabWidget.setSizePolicy(sizePolicy) + MainWindow.tabWidget.setMinimumSize(QtCore.QSize(0, 120)) + MainWindow.tabWidget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.tabWidget.setStyleSheet("QTabWidget::pane { /* The tab widget frame */\n" +" border-bottom: 6px solid;\n" +" border-bottom-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgb(200, 200, 200), stop:1 rgba(220,220,220));\n" +" border-top: 8px solid rgb(0,0,128);\n" +" /*border-radius: 4px;*/\n" +"}\n" +"\n" +"\n" +"QTabWidget::tab-bar {\n" +" left: 20px; /* move to the right by 5px */\n" +" bottom: -8px;\n" +"}\n" +"\n" +"QTabBar::tab {\n" +" /*border-bottom-color: transparent;\n" +" border-top-left-radius: 4px;*/\n" +" min-width: 18ex;\n" +" padding: 4px;\n" +"}\n" +"\n" +"QTabBar::tab:selected {\n" +" background: rgb(240,240,240);\n" +" border: 2px solid rgb(200,200,200);\n" +" border-bottom: 0 px solid;\n" +" border-top-left-radius: 6px;\n" +" border-top-right-radius: 6px;\n" +"}\n" +"\n" +"QTabBar::tab:!selected {\n" +" border: 2px solid rgb(200,200,200);\n" +" margin-top: 4px; /* make non-selected tabs look smaller */\n" +" border-top-left-radius: 6px;\n" +" border-top-right-radius: 6px;\n" +"}") + MainWindow.tabWidget.setObjectName("tabWidget") + MainWindow.tab_2 = QtWidgets.QWidget() + MainWindow.tab_2.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_2.setObjectName("tab_2") + MainWindow.layoutWidget = QtWidgets.QWidget(MainWindow.tab_2) + MainWindow.layoutWidget.setGeometry(QtCore.QRect(0, 0, 1100, 81)) + MainWindow.layoutWidget.setObjectName("layoutWidget") + MainWindow.horizontalLayout_2 = QtWidgets.QHBoxLayout(MainWindow.layoutWidget) + MainWindow.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_2.addItem(spacerItem) + MainWindow.gridLayout = QtWidgets.QGridLayout() + MainWindow.gridLayout.setObjectName("gridLayout") + MainWindow.zoomOutButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.zoomOutButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/Images/zoom_out.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.zoomOutButtonSurface.setIcon(icon) + MainWindow.zoomOutButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomOutButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomOutButtonSurface.setObjectName("zoomOutButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.zoomOutButtonSurface, 0, 1, 1, 1) + MainWindow.arrowButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.arrowButtonSurface.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.arrowButtonSurface.setFocusPolicy(QtCore.Qt.TabFocus) + MainWindow.arrowButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/Images/select.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.arrowButtonSurface.setIcon(icon1) + MainWindow.arrowButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.arrowButtonSurface.setCheckable(False) + MainWindow.arrowButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.arrowButtonSurface.setObjectName("arrowButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.arrowButtonSurface, 0, 0, 1, 1) + MainWindow.panningButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.panningButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/Images/pan.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.panningButtonSurface.setIcon(icon2) + MainWindow.panningButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.panningButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.panningButtonSurface.setObjectName("panningButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.panningButtonSurface, 1, 0, 1, 1) + MainWindow.zoomInButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.zoomInButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/Images/zoom_in.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.zoomInButtonSurface.setIcon(icon3) + MainWindow.zoomInButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomInButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomInButtonSurface.setObjectName("zoomInButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.zoomInButtonSurface, 1, 1, 1, 1) + MainWindow.horizontalLayout_2.addLayout(MainWindow.gridLayout) + MainWindow.line_2 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_2.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_2.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_2.setLineWidth(1) + MainWindow.line_2.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_2.setObjectName("line_2") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_2) + MainWindow.verticalLayout_7 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_7.setObjectName("verticalLayout_7") + MainWindow.polyButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.polyButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap(":/Images/polygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.polyButton.setIcon(icon4) + MainWindow.polyButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.polyButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.polyButton.setObjectName("polyButton") + MainWindow.verticalLayout_7.addWidget(MainWindow.polyButton) + MainWindow.rectButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.rectButton.setEnabled(True) + MainWindow.rectButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(":/Images/rectangle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.rectButton.setIcon(icon5) + MainWindow.rectButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.rectButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.rectButton.setObjectName("rectButton") + MainWindow.verticalLayout_7.addWidget(MainWindow.rectButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_7) + MainWindow.verticalLayout_10 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_10.setObjectName("verticalLayout_10") + MainWindow.addPolyHoleButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.addPolyHoleButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap(":/Images/polygon_hole.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.addPolyHoleButton.setIcon(icon6) + MainWindow.addPolyHoleButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.addPolyHoleButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.addPolyHoleButton.setObjectName("addPolyHoleButton") + MainWindow.verticalLayout_10.addWidget(MainWindow.addPolyHoleButton) + MainWindow.addRectHoleButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.addRectHoleButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(":/Images/rectangle_hole.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.addRectHoleButton.setIcon(icon7) + MainWindow.addRectHoleButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.addRectHoleButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.addRectHoleButton.setObjectName("addRectHoleButton") + MainWindow.verticalLayout_10.addWidget(MainWindow.addRectHoleButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_10) + MainWindow.verticalLayout_12 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_12.setObjectName("verticalLayout_12") + MainWindow.mergeButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.mergeButton.sizePolicy().hasHeightForWidth()) + MainWindow.mergeButton.setSizePolicy(sizePolicy) + MainWindow.mergeButton.setLayoutDirection(QtCore.Qt.LeftToRight) + MainWindow.mergeButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon8 = QtGui.QIcon() + icon8.addPixmap(QtGui.QPixmap(":/Images/merge.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.mergeButton.setIcon(icon8) + MainWindow.mergeButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.mergeButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.mergeButton.setAutoRaise(False) + MainWindow.mergeButton.setObjectName("mergeButton") + MainWindow.verticalLayout_12.addWidget(MainWindow.mergeButton) + MainWindow.deleteButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.deleteButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(":/Images/erase.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.deleteButton.setIcon(icon9) + MainWindow.deleteButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.deleteButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.deleteButton.setObjectName("deleteButton") + MainWindow.verticalLayout_12.addWidget(MainWindow.deleteButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_12) + MainWindow.line_5 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_5.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_5.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_5.setLineWidth(1) + MainWindow.line_5.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_5.setObjectName("line_5") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_5) + MainWindow.verticalLayout_9 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_9.setObjectName("verticalLayout_9") + MainWindow.gridSnapButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridSnapButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap(":/Images/grid_snap.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridSnapButtonSurface.setIcon(icon10) + MainWindow.gridSnapButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSnapButtonSurface.setCheckable(True) + MainWindow.gridSnapButtonSurface.setChecked(True) + MainWindow.gridSnapButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSnapButtonSurface.setObjectName("gridSnapButtonSurface") + MainWindow.verticalLayout_9.addWidget(MainWindow.gridSnapButtonSurface) + MainWindow.gridButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon11 = QtGui.QIcon() + icon11.addPixmap(QtGui.QPixmap(":/Images/grid.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridButtonSurface.setIcon(icon11) + MainWindow.gridButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridButtonSurface.setCheckable(True) + MainWindow.gridButtonSurface.setChecked(True) + MainWindow.gridButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridButtonSurface.setObjectName("gridButtonSurface") + MainWindow.verticalLayout_9.addWidget(MainWindow.gridButtonSurface) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_9) + MainWindow.verticalLayout_8 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_8.setObjectName("verticalLayout_8") + MainWindow.gridSpacingSpinBox = QtWidgets.QSpinBox(MainWindow.layoutWidget) + MainWindow.gridSpacingSpinBox.setMinimum(5) + MainWindow.gridSpacingSpinBox.setMaximum(1000) + MainWindow.gridSpacingSpinBox.setSingleStep(10) + MainWindow.gridSpacingSpinBox.setProperty("value", 20) + MainWindow.gridSpacingSpinBox.setObjectName("gridSpacingSpinBox") + MainWindow.verticalLayout_8.addWidget(MainWindow.gridSpacingSpinBox) + MainWindow.gridSpacingButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridSpacingButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon12 = QtGui.QIcon() + icon12.addPixmap(QtGui.QPixmap(":/Images/grid_settings.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridSpacingButton.setIcon(icon12) + MainWindow.gridSpacingButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSpacingButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSpacingButton.setObjectName("gridSpacingButton") + MainWindow.verticalLayout_8.addWidget(MainWindow.gridSpacingButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_8) + MainWindow.line_6 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_6.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_6.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_6.setLineWidth(1) + MainWindow.line_6.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_6.setObjectName("line_6") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_6) + MainWindow.verticalLayout_11 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_11.setObjectName("verticalLayout_11") + MainWindow.loadGeometryButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.loadGeometryButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon13 = QtGui.QIcon() + icon13.addPixmap(QtGui.QPixmap(":/Images/open.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.loadGeometryButton.setIcon(icon13) + MainWindow.loadGeometryButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.loadGeometryButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.loadGeometryButton.setObjectName("loadGeometryButton") + MainWindow.verticalLayout_11.addWidget(MainWindow.loadGeometryButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_11) + MainWindow.tabWidget.addTab(MainWindow.tab_2, "") + MainWindow.tab = QtWidgets.QWidget() + MainWindow.tab.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab.setObjectName("tab") + MainWindow.horizontalLayoutWidget_2 = QtWidgets.QWidget(MainWindow.tab) + MainWindow.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 0, 464, 81)) + MainWindow.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2") + MainWindow.horizontalLayout_3 = QtWidgets.QHBoxLayout(MainWindow.horizontalLayoutWidget_2) + MainWindow.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_3.setObjectName("horizontalLayout_3") + spacerItem1 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_3.addItem(spacerItem1) + MainWindow.gridLayout_2 = QtWidgets.QGridLayout() + MainWindow.gridLayout_2.setObjectName("gridLayout_2") + MainWindow.arrowButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.arrowButtonBorder.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.arrowButtonBorder.setFocusPolicy(QtCore.Qt.TabFocus) + MainWindow.arrowButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.arrowButtonBorder.setIcon(icon1) + MainWindow.arrowButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.arrowButtonBorder.setCheckable(True) + MainWindow.arrowButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.arrowButtonBorder.setObjectName("arrowButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.arrowButtonBorder, 0, 0, 1, 1) + MainWindow.zoomOutButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.zoomOutButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.zoomOutButtonBorder.setIcon(icon) + MainWindow.zoomOutButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomOutButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomOutButtonBorder.setObjectName("zoomOutButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.zoomOutButtonBorder, 0, 1, 1, 1) + MainWindow.zoomInButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.zoomInButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.zoomInButtonBorder.setIcon(icon3) + MainWindow.zoomInButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomInButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomInButtonBorder.setObjectName("zoomInButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.zoomInButtonBorder, 1, 1, 1, 1) + MainWindow.panningButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.panningButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.panningButtonBorder.setIcon(icon2) + MainWindow.panningButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.panningButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.panningButtonBorder.setObjectName("panningButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.panningButtonBorder, 1, 0, 1, 1) + MainWindow.horizontalLayout_3.addLayout(MainWindow.gridLayout_2) + MainWindow.line = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget_2) + MainWindow.line.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line.setObjectName("line") + MainWindow.horizontalLayout_3.addWidget(MainWindow.line) + MainWindow.verticalLayout_6 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_6.setObjectName("verticalLayout_6") + MainWindow.setMarkerButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.setMarkerButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon14 = QtGui.QIcon() + icon14.addPixmap(QtGui.QPixmap(":/Images/add_marker.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.setMarkerButton.setIcon(icon14) + MainWindow.setMarkerButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.setMarkerButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.setMarkerButton.setObjectName("setMarkerButton") + MainWindow.verticalLayout_6.addWidget(MainWindow.setMarkerButton) + MainWindow.splitEdgeButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.splitEdgeButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon15 = QtGui.QIcon() + icon15.addPixmap(QtGui.QPixmap(":/Images/split_edge.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.splitEdgeButton.setIcon(icon15) + MainWindow.splitEdgeButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.splitEdgeButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.splitEdgeButton.setObjectName("splitEdgeButton") + MainWindow.verticalLayout_6.addWidget(MainWindow.splitEdgeButton) + MainWindow.horizontalLayout_3.addLayout(MainWindow.verticalLayout_6) + MainWindow.line_3 = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget_2) + MainWindow.line_3.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_3.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_3.setObjectName("line_3") + MainWindow.horizontalLayout_3.addWidget(MainWindow.line_3) + MainWindow.verticalLayout_13 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_13.setObjectName("verticalLayout_13") + MainWindow.gridSnapButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.gridSnapButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + MainWindow.gridSnapButtonBorder.setIcon(icon10) + MainWindow.gridSnapButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSnapButtonBorder.setCheckable(True) + MainWindow.gridSnapButtonBorder.setChecked(True) + MainWindow.gridSnapButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSnapButtonBorder.setObjectName("gridSnapButtonBorder") + MainWindow.verticalLayout_13.addWidget(MainWindow.gridSnapButtonBorder) + MainWindow.gridButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.gridButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + MainWindow.gridButtonBorder.setIcon(icon11) + MainWindow.gridButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridButtonBorder.setCheckable(True) + MainWindow.gridButtonBorder.setChecked(True) + MainWindow.gridButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridButtonBorder.setObjectName("gridButtonBorder") + MainWindow.verticalLayout_13.addWidget(MainWindow.gridButtonBorder) + MainWindow.horizontalLayout_3.addLayout(MainWindow.verticalLayout_13) + MainWindow.tabWidget.addTab(MainWindow.tab, "") + MainWindow.tab_4 = QtWidgets.QWidget() + MainWindow.tab_4.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_4.setObjectName("tab_4") + MainWindow.saveGeomButton = QtWidgets.QToolButton(MainWindow.tab_4) + MainWindow.saveGeomButton.setGeometry(QtCore.QRect(10, 30, 141, 21)) + MainWindow.saveGeomButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon16 = QtGui.QIcon() + icon16.addPixmap(QtGui.QPixmap(":/Images/save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.saveGeomButton.setIcon(icon16) + MainWindow.saveGeomButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.saveGeomButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveGeomButton.setObjectName("saveGeomButton") + MainWindow.tabWidget.addTab(MainWindow.tab_4, "") + MainWindow.tab_3 = QtWidgets.QWidget() + MainWindow.tab_3.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_3.setObjectName("tab_3") + MainWindow.horizontalLayoutWidget = QtWidgets.QWidget(MainWindow.tab_3) + MainWindow.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 0, 351, 71)) + MainWindow.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") + MainWindow.horizontalLayout_5 = QtWidgets.QHBoxLayout(MainWindow.horizontalLayoutWidget) + MainWindow.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_5.setSpacing(0) + MainWindow.horizontalLayout_5.setObjectName("horizontalLayout_5") + MainWindow.label_9 = QtWidgets.QLabel(MainWindow.horizontalLayoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.label_9.sizePolicy().hasHeightForWidth()) + MainWindow.label_9.setSizePolicy(sizePolicy) + MainWindow.label_9.setText("") + MainWindow.label_9.setPixmap(QtGui.QPixmap(":/Images/save.png")) + MainWindow.label_9.setObjectName("label_9") + MainWindow.horizontalLayout_5.addWidget(MainWindow.label_9) + MainWindow.line_4 = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget) + MainWindow.line_4.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) + MainWindow.line_4.setObjectName("line_4") + MainWindow.horizontalLayout_5.addWidget(MainWindow.line_4) + MainWindow.verticalLayout_19 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_19.setSpacing(0) + MainWindow.verticalLayout_19.setObjectName("verticalLayout_19") + MainWindow.saveMeshButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + MainWindow.saveMeshButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon17 = QtGui.QIcon() + icon17.addPixmap(QtGui.QPixmap(":/Images/blank.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.saveMeshButton.setIcon(icon17) + MainWindow.saveMeshButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveMeshButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveMeshButton.setObjectName("saveMeshButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveMeshButton) + MainWindow.saveArraysButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + MainWindow.saveArraysButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.saveArraysButton.setIcon(icon17) + MainWindow.saveArraysButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveArraysButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveArraysButton.setObjectName("saveArraysButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveArraysButton) + MainWindow.saveArraysMatlabButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.saveArraysMatlabButton.sizePolicy().hasHeightForWidth()) + MainWindow.saveArraysMatlabButton.setSizePolicy(sizePolicy) + MainWindow.saveArraysMatlabButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.saveArraysMatlabButton.setIcon(icon17) + MainWindow.saveArraysMatlabButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveArraysMatlabButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveArraysMatlabButton.setObjectName("saveArraysMatlabButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveArraysMatlabButton) + MainWindow.horizontalLayout_5.addLayout(MainWindow.verticalLayout_19) + MainWindow.tabWidget.addTab(MainWindow.tab_3, "") + MainWindow.verticalLayout_2.addWidget(MainWindow.tabWidget) + MainWindow.horizontalLayout_4 = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem2) + MainWindow.labelTooltip = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelTooltip.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelTooltip.setText("") + MainWindow.labelTooltip.setObjectName("labelTooltip") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelTooltip) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem3) + MainWindow.label = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.label.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.label.setObjectName("label") + MainWindow.horizontalLayout_4.addWidget(MainWindow.label) + MainWindow.labelX = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelX.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelX.setObjectName("labelX") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelX) + MainWindow.label_3 = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.label_3.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.label_3.setObjectName("label_3") + MainWindow.horizontalLayout_4.addWidget(MainWindow.label_3) + MainWindow.labelY = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelY.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelY.setObjectName("labelY") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelY) + spacerItem4 = QtWidgets.QSpacerItem(220, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem4) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout_4) + MainWindow.horizontalLayout = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout.setSpacing(0) + MainWindow.horizontalLayout.setObjectName("horizontalLayout") + MainWindow.stackedWidget = QtWidgets.QStackedWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.stackedWidget.sizePolicy().hasHeightForWidth()) + MainWindow.stackedWidget.setSizePolicy(sizePolicy) + MainWindow.stackedWidget.setMinimumSize(QtCore.QSize(661, 420)) + MainWindow.stackedWidget.setStyleSheet("QStackedWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.stackedWidget.setObjectName("stackedWidget") + MainWindow.page = QtWidgets.QWidget() + MainWindow.page.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page.setObjectName("page") + MainWindow.verticalLayout_4 = QtWidgets.QVBoxLayout(MainWindow.page) + MainWindow.verticalLayout_4.setObjectName("verticalLayout_4") + MainWindow.verticalLayout = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout.setObjectName("verticalLayout") + MainWindow.verticalLayout_4.addLayout(MainWindow.verticalLayout) + MainWindow.stackedWidget.addWidget(MainWindow.page) + MainWindow.page_2 = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.page_2.sizePolicy().hasHeightForWidth()) + MainWindow.page_2.setSizePolicy(sizePolicy) + MainWindow.page_2.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_2.setObjectName("page_2") + MainWindow.verticalLayout_3 = QtWidgets.QVBoxLayout(MainWindow.page_2) + MainWindow.verticalLayout_3.setObjectName("verticalLayout_3") + MainWindow.graphicsView = QtWidgets.QGraphicsView(MainWindow.page_2) + MainWindow.graphicsView.setMinimumSize(QtCore.QSize(661, 401)) + MainWindow.graphicsView.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.graphicsView.setMouseTracking(True) + MainWindow.graphicsView.setStyleSheet("QGraphicsView{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.graphicsView.setObjectName("graphicsView") + MainWindow.verticalLayout_3.addWidget(MainWindow.graphicsView) + MainWindow.stackedWidget.addWidget(MainWindow.page_2) + MainWindow.horizontalLayout.addWidget(MainWindow.stackedWidget) + MainWindow.stackedWidgetRight = QtWidgets.QStackedWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.stackedWidgetRight.sizePolicy().hasHeightForWidth()) + MainWindow.stackedWidgetRight.setSizePolicy(sizePolicy) + MainWindow.stackedWidgetRight.setMinimumSize(QtCore.QSize(200, 401)) + MainWindow.stackedWidgetRight.setStyleSheet("QStackedWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.stackedWidgetRight.setObjectName("stackedWidgetRight") + MainWindow.page_5 = QtWidgets.QWidget() + MainWindow.page_5.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_5.setObjectName("page_5") + MainWindow.verticalLayout_14 = QtWidgets.QVBoxLayout(MainWindow.page_5) + MainWindow.verticalLayout_14.setObjectName("verticalLayout_14") + MainWindow.verticalLayout_15 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_15.setObjectName("verticalLayout_15") + MainWindow.widget = QtWidgets.QWidget(MainWindow.page_5) + MainWindow.widget.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.widget.setObjectName("widget") + MainWindow.gridLayout_3 = QtWidgets.QGridLayout(MainWindow.widget) + MainWindow.gridLayout_3.setObjectName("gridLayout_3") + MainWindow.label_4 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_4.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_4.setObjectName("label_4") + MainWindow.gridLayout_3.addWidget(MainWindow.label_4, 5, 0, 1, 1) + MainWindow.elSizeSpinBox = QtWidgets.QDoubleSpinBox(MainWindow.widget) + MainWindow.elSizeSpinBox.setStyleSheet("QDoubleSpinBox{\n" +" background: rgb(255,255,255);\n" +" border: 1px solid rgb(0,0,128);\n" +"}") + MainWindow.elSizeSpinBox.setDecimals(1) + MainWindow.elSizeSpinBox.setMinimum(0.0) + MainWindow.elSizeSpinBox.setMaximum(1000.0) + MainWindow.elSizeSpinBox.setSingleStep(5.0) + MainWindow.elSizeSpinBox.setProperty("value", 25.0) + MainWindow.elSizeSpinBox.setObjectName("elSizeSpinBox") + MainWindow.gridLayout_3.addWidget(MainWindow.elSizeSpinBox, 5, 1, 1, 1) + MainWindow.radioButtonQuadrangle = QtWidgets.QRadioButton(MainWindow.widget) + MainWindow.radioButtonQuadrangle.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonQuadrangle.setChecked(False) + MainWindow.radioButtonQuadrangle.setObjectName("radioButtonQuadrangle") + MainWindow.gridLayout_3.addWidget(MainWindow.radioButtonQuadrangle, 2, 1, 1, 1) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.gridLayout_3.addItem(spacerItem5, 10, 0, 1, 1) + MainWindow.label_5 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_5.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_5.setObjectName("label_5") + MainWindow.gridLayout_3.addWidget(MainWindow.label_5, 7, 0, 1, 1) + MainWindow.DOFSpinBox = QtWidgets.QSpinBox(MainWindow.widget) + MainWindow.DOFSpinBox.setStyleSheet("QSpinBox{\n" +" background: rgb(255,255,255);\n" +" border: 1px solid rgb(0,0,128);\n" +"}") + MainWindow.DOFSpinBox.setMinimum(1) + MainWindow.DOFSpinBox.setObjectName("DOFSpinBox") + MainWindow.gridLayout_3.addWidget(MainWindow.DOFSpinBox, 7, 1, 1, 1) + MainWindow.radioButtonTriangle = QtWidgets.QRadioButton(MainWindow.widget) + MainWindow.radioButtonTriangle.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonTriangle.setChecked(True) + MainWindow.radioButtonTriangle.setObjectName("radioButtonTriangle") + MainWindow.gridLayout_3.addWidget(MainWindow.radioButtonTriangle, 0, 1, 1, 1) + spacerItem6 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem6, 4, 1, 1, 1) + spacerItem7 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem7, 6, 1, 1, 1) + MainWindow.label_2 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_2.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_2.setObjectName("label_2") + MainWindow.gridLayout_3.addWidget(MainWindow.label_2, 0, 0, 1, 1) + spacerItem8 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem8, 8, 1, 1, 1) + MainWindow.refreshMeshButton = QtWidgets.QPushButton(MainWindow.widget) + MainWindow.refreshMeshButton.setObjectName("refreshMeshButton") + MainWindow.gridLayout_3.addWidget(MainWindow.refreshMeshButton, 9, 1, 1, 1) + MainWindow.verticalLayout_15.addWidget(MainWindow.widget) + MainWindow.verticalLayout_14.addLayout(MainWindow.verticalLayout_15) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_5) + MainWindow.page_6 = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.page_6.sizePolicy().hasHeightForWidth()) + MainWindow.page_6.setSizePolicy(sizePolicy) + MainWindow.page_6.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_6.setObjectName("page_6") + MainWindow.verticalLayout_16 = QtWidgets.QVBoxLayout(MainWindow.page_6) + MainWindow.verticalLayout_16.setObjectName("verticalLayout_16") + MainWindow.scrollArea = QtWidgets.QScrollArea(MainWindow.page_6) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.scrollArea.sizePolicy().hasHeightForWidth()) + MainWindow.scrollArea.setSizePolicy(sizePolicy) + MainWindow.scrollArea.setMinimumSize(QtCore.QSize(200, 300)) + MainWindow.scrollArea.setStyleSheet("QScrollArea{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) + MainWindow.scrollArea.setWidgetResizable(True) + MainWindow.scrollArea.setObjectName("scrollArea") + MainWindow.scrollAreaWidgetContents_2 = QtWidgets.QWidget() + MainWindow.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 196, 296)) + MainWindow.scrollAreaWidgetContents_2.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +"}") + MainWindow.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") + MainWindow.scrollArea.setWidget(MainWindow.scrollAreaWidgetContents_2) + MainWindow.verticalLayout_16.addWidget(MainWindow.scrollArea) + spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.verticalLayout_16.addItem(spacerItem9) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_6) + MainWindow.page_7 = QtWidgets.QWidget() + MainWindow.page_7.setObjectName("page_7") + MainWindow.verticalLayout_5 = QtWidgets.QVBoxLayout(MainWindow.page_7) + MainWindow.verticalLayout_5.setObjectName("verticalLayout_5") + MainWindow.widget_2 = QtWidgets.QWidget(MainWindow.page_7) + MainWindow.widget_2.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.widget_2.setObjectName("widget_2") + MainWindow.gridLayout_4 = QtWidgets.QGridLayout(MainWindow.widget_2) + MainWindow.gridLayout_4.setObjectName("gridLayout_4") + spacerItem10 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_4.addItem(spacerItem10, 2, 1, 1, 1) + MainWindow.radioButtonDisplayPointLabelsTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayPointLabelsTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayPointLabelsTrue.setChecked(True) + MainWindow.radioButtonDisplayPointLabelsTrue.setObjectName("radioButtonDisplayPointLabelsTrue") + MainWindow.buttonGroupDisplayPointLabels = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDisplayPointLabels.setObjectName("buttonGroupDisplayPointLabels") + MainWindow.buttonGroupDisplayPointLabels.addButton(MainWindow.radioButtonDisplayPointLabelsTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayPointLabelsTrue, 3, 1, 1, 1) + MainWindow.radioButtonDisplayEdgeLabelsTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayEdgeLabelsTrue.setChecked(True) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setObjectName("radioButtonDisplayEdgeLabelsTrue") + MainWindow.buttonGroupDOFsPerNode = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDOFsPerNode.setObjectName("buttonGroupDOFsPerNode") + MainWindow.buttonGroupDOFsPerNode.addButton(MainWindow.radioButtonDisplayEdgeLabelsTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayEdgeLabelsTrue, 6, 1, 1, 1) + MainWindow.radioButtonDisplayPointLabelsFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayPointLabelsFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayPointLabelsFalse.setObjectName("radioButtonDisplayPointLabelsFalse") + MainWindow.buttonGroupDisplayPointLabels.addButton(MainWindow.radioButtonDisplayPointLabelsFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayPointLabelsFalse, 4, 1, 1, 1) + MainWindow.radioButtonDrawPointFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDrawPointFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDrawPointFalse.setObjectName("radioButtonDrawPointFalse") + MainWindow.buttonGroupDrawPoints = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDrawPoints.setObjectName("buttonGroupDrawPoints") + MainWindow.buttonGroupDrawPoints.addButton(MainWindow.radioButtonDrawPointFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDrawPointFalse, 1, 1, 1, 1) + MainWindow.radioButtonDrawPointTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDrawPointTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDrawPointTrue.setChecked(True) + MainWindow.radioButtonDrawPointTrue.setObjectName("radioButtonDrawPointTrue") + MainWindow.buttonGroupDrawPoints.addButton(MainWindow.radioButtonDrawPointTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDrawPointTrue, 0, 1, 1, 1) + MainWindow.label_8 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_8.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_8.setObjectName("label_8") + MainWindow.gridLayout_4.addWidget(MainWindow.label_8, 3, 0, 1, 1) + MainWindow.label_6 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_6.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_6.setObjectName("label_6") + MainWindow.gridLayout_4.addWidget(MainWindow.label_6, 0, 0, 1, 1) + MainWindow.label_7 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_7.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_7.setObjectName("label_7") + MainWindow.gridLayout_4.addWidget(MainWindow.label_7, 6, 0, 1, 1) + spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.gridLayout_4.addItem(spacerItem11, 8, 0, 1, 1) + MainWindow.radioButtonDisplayEdgeLabelsFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayEdgeLabelsFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayEdgeLabelsFalse.setObjectName("radioButtonDisplayEdgeLabelsFalse") + MainWindow.buttonGroupDOFsPerNode.addButton(MainWindow.radioButtonDisplayEdgeLabelsFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayEdgeLabelsFalse, 7, 1, 1, 1) + spacerItem12 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_4.addItem(spacerItem12, 5, 1, 1, 1) + MainWindow.verticalLayout_5.addWidget(MainWindow.widget_2) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_7) + MainWindow.horizontalLayout.addWidget(MainWindow.stackedWidgetRight) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout) + MainWindow.horizontalLayout_7 = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout_7.setObjectName("horizontalLayout_7") + spacerItem13 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_7.addItem(spacerItem13) + MainWindow.verticalLayout_17 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_17.setObjectName("verticalLayout_17") + MainWindow.textBrowser = QtWidgets.QTextBrowser(MainWindow.centralwidget) + MainWindow.textBrowser.setMaximumSize(QtCore.QSize(16777215, 150)) + MainWindow.textBrowser.setStyleSheet("QTextBrowser{\n" +"border: 2px solid rgb(0,0,128);\n" +"background: rgb(255,255,255);\n" +"}") + MainWindow.textBrowser.setObjectName("textBrowser") + MainWindow.verticalLayout_17.addWidget(MainWindow.textBrowser) + MainWindow.horizontalLayout_7.addLayout(MainWindow.verticalLayout_17) + MainWindow.verticalLayout_18 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_18.setObjectName("verticalLayout_18") + MainWindow.hideTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.hideTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}") + MainWindow.hideTextBrowserButton.setText("") + icon18 = QtGui.QIcon() + icon18.addPixmap(QtGui.QPixmap(":/Images/minus.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.hideTextBrowserButton.setIcon(icon18) + MainWindow.hideTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.hideTextBrowserButton.setObjectName("hideTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.hideTextBrowserButton) + MainWindow.showTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.showTextBrowserButton.setEnabled(True) + MainWindow.showTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}") + MainWindow.showTextBrowserButton.setText("") + icon19 = QtGui.QIcon() + icon19.addPixmap(QtGui.QPixmap(":/Images/plus.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.showTextBrowserButton.setIcon(icon19) + MainWindow.showTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.showTextBrowserButton.setObjectName("showTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.showTextBrowserButton) + MainWindow.clearTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.clearTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.clearTextBrowserButton.setText("") + MainWindow.clearTextBrowserButton.setIcon(icon9) + MainWindow.clearTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.clearTextBrowserButton.setObjectName("clearTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.clearTextBrowserButton) + MainWindow.horizontalLayout_7.addLayout(MainWindow.verticalLayout_18) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout_7) + MainWindow.setCentralWidget(MainWindow.centralwidget) + MainWindow.menubar = QtWidgets.QMenuBar(MainWindow) + MainWindow.menubar.setGeometry(QtCore.QRect(0, 0, 1493, 21)) + MainWindow.menubar.setObjectName("menubar") + MainWindow.setMenuBar(MainWindow.menubar) + MainWindow.statusbar = QtWidgets.QStatusBar(MainWindow) + MainWindow.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(MainWindow.statusbar) + + self.retranslateUi(MainWindow) + MainWindow.tabWidget.setCurrentIndex(0) + MainWindow.stackedWidget.setCurrentIndex(1) + MainWindow.stackedWidgetRight.setCurrentIndex(1) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + MainWindow.zoomOutButtonSurface.setText(_translate("MainWindow", "Zoom Out")) + MainWindow.arrowButtonSurface.setText(_translate("MainWindow", "Arrow")) + MainWindow.panningButtonSurface.setText(_translate("MainWindow", "Panning")) + MainWindow.zoomInButtonSurface.setText(_translate("MainWindow", "Zoom In")) + MainWindow.polyButton.setText(_translate("MainWindow", "Draw Polygon")) + MainWindow.rectButton.setText(_translate("MainWindow", "Draw Rectangle")) + MainWindow.addPolyHoleButton.setText(_translate("MainWindow", "Draw Polygon Hole")) + MainWindow.addRectHoleButton.setText(_translate("MainWindow", "Draw Rectangle Hole")) + MainWindow.mergeButton.setText(_translate("MainWindow", "Merge Overlapping Geometries")) + MainWindow.deleteButton.setText(_translate("MainWindow", "Delete Item")) + MainWindow.gridSnapButtonSurface.setText(_translate("MainWindow", "Toggle Gridsnap")) + MainWindow.gridButtonSurface.setText(_translate("MainWindow", "Toggle Grid")) + MainWindow.gridSpacingButton.setText(_translate("MainWindow", "Set Grid Spacing")) + MainWindow.loadGeometryButton.setText(_translate("MainWindow", "Load Geometry")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_2), _translate("MainWindow", "Page")) + MainWindow.arrowButtonBorder.setText(_translate("MainWindow", "Arrow")) + MainWindow.zoomOutButtonBorder.setText(_translate("MainWindow", "Zoom Out")) + MainWindow.zoomInButtonBorder.setText(_translate("MainWindow", "Zoom In")) + MainWindow.panningButtonBorder.setText(_translate("MainWindow", "Panning")) + MainWindow.setMarkerButton.setText(_translate("MainWindow", "Set Marker")) + MainWindow.splitEdgeButton.setText(_translate("MainWindow", "Split Edge")) + MainWindow.gridSnapButtonBorder.setText(_translate("MainWindow", "Toggle Gridsnap")) + MainWindow.gridButtonBorder.setText(_translate("MainWindow", "Toggle Grid")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab), _translate("MainWindow", "Tab 1")) + MainWindow.saveGeomButton.setText(_translate("MainWindow", "Save Geometry")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_4), _translate("MainWindow", "Page")) + MainWindow.saveMeshButton.setText(_translate("MainWindow", "Save Mesh")) + MainWindow.saveArraysButton.setText(_translate("MainWindow", "Save Mesh Arrays")) + MainWindow.saveArraysMatlabButton.setText(_translate("MainWindow", "Save Mesh Arrays to Matlab")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_3), _translate("MainWindow", "Page")) + MainWindow.label.setText(_translate("MainWindow", "x: ")) + MainWindow.labelX.setText(_translate("MainWindow", "TextLabel")) + MainWindow.label_3.setText(_translate("MainWindow", "y:")) + MainWindow.labelY.setText(_translate("MainWindow", "TextLabel")) + MainWindow.label_4.setText(_translate("MainWindow", "Element Size:")) + MainWindow.radioButtonQuadrangle.setText(_translate("MainWindow", "Quadrangle")) + MainWindow.label_5.setText(_translate("MainWindow", "DOFs per Node:")) + MainWindow.radioButtonTriangle.setText(_translate("MainWindow", "Triangle")) + MainWindow.label_2.setText(_translate("MainWindow", "Element Type:")) + MainWindow.refreshMeshButton.setText(_translate("MainWindow", "Refresh Mesh")) + MainWindow.radioButtonDisplayPointLabelsTrue.setText(_translate("MainWindow", "True")) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setText(_translate("MainWindow", "True")) + MainWindow.radioButtonDisplayPointLabelsFalse.setText(_translate("MainWindow", "False")) + MainWindow.radioButtonDrawPointFalse.setText(_translate("MainWindow", "False")) + MainWindow.radioButtonDrawPointTrue.setText(_translate("MainWindow", "True")) + MainWindow.label_8.setText(_translate("MainWindow", "Display Point Labels:")) + MainWindow.label_6.setText(_translate("MainWindow", "Draw Points:")) + MainWindow.label_7.setText(_translate("MainWindow", "Display Edge Labels")) + MainWindow.radioButtonDisplayEdgeLabelsFalse.setText(_translate("MainWindow", "False")) + MainWindow.textBrowser.setHtml(_translate("MainWindow", "\n" +"\n" +"


")) + +#import resources_rc diff --git a/calfem/vis_mpl.py b/calfem/vis_mpl.py index 888f181..b000c13 100644 --- a/calfem/vis_mpl.py +++ b/calfem/vis_mpl.py @@ -1581,127 +1581,288 @@ def eldisp2(ex, ey, ed, plotpar=[2, 1, 1], sfac=None): # hold off # %--------------------------end-------------------------------- -def secforce2(ex, ey, es, plotpar=None, sfac=None, eci = None): - """ - -------------------------------------------------------------------------- - PURPOSE: - Draw section force diagram for a two dimensional bar or beam element. - INPUT: - ex = [ x1 x2 ] - ey = [ y1 y2 ] element node coordinates. +def dispbeam2(ex, ey, edi, plotpar=[2, 1, 1], sfac=None): + """ + dispbeam2(ex,ey,edi,plotpar,sfac) + [sfac]=dispbeam2(ex,ey,edi) + [sfac]=dispbeam2(ex,ey,edi,plotpar) +------------------------------------------------------------------------ + PURPOSE + Draw the displacement diagram for a two dimensional beam element. + + INPUT: ex = [ x1 x2 ] + ey = [ y1 y2 ] element node coordinates. + + edi = [ u1 v1; + u2 v2; + .....] matrix containing the displacements + in Nbr evaluation points along the beam. + + plotpar=[linetype, linecolour, nodemark] + + linetype=1 -> solid linecolour=1 -> black + 2 -> dashed 2 -> blue + 3 -> dotted 3 -> magenta + 4 -> red + nodemark=0 -> no mark + 1 -> circle + 2 -> star + 3 -> point + + sfac = [scalar] scale factor for displacements. + + Rem. Default if sfac and plotpar is left out is auto magnification + and dashed black lines with circles at nodes -> plotpar=[1 1 1] +------------------------------------------------------------------------ + + LAST MODIFIED: O Dahlblom 2015-11-18 + O Dahlblom 2023-01-31 (Python) - es = [ S1; - S2; - ... ] vector containing the section force - in Nbr evaluation points along the element. + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University +------------------------------------------------------------------------ + """ + if ex.shape != ey.shape: + raise ValueError("Check size of ex, ey dimensions.") - plotpar=[linecolour, elementcolour] + rows, cols = edi.shape + if cols != 2: + raise ValueError("Check size of edi dimension.") + Nbr = rows + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + nxX=dx/L + nyX=dy/L + n = np.array([nxX, nyX]) + + line_color, line_style, node_color, node_style = pltstyle2(plotpar) + + if sfac is None: + sfac=(0.1*L)/(np.max(abs(edi))) + + eci = np.arange(0., L+L/(Nbr-1), L/(Nbr-1)).reshape(Nbr,1) + + edi1=edi*sfac +# From local x-coordinates to global coordinates of the beam element. + A = np.zeros(2*Nbr).reshape(Nbr,2) + A[0,0] = ex[0] + A[0,1] = ey[0] + for i in range(1, Nbr): + A[i,0]=A[0,0]+eci[i]*n[0] + A[i,1]=A[0,1]+eci[i]*n[1] + + for i in range(0, Nbr): + A[i,0]=A[i,0]+edi1[i,0]*n[0]-edi1[i,1]*n[1] + A[i,1]=A[i,1]+edi1[i,0]*n[1]+edi1[i,1]*n[0] + xc=np.array(A[:,0]) + yc=np.array(A[:,1]) + + plt.plot(xc,yc, color=line_color, linewidth=1) + + A1=np.array([A[0,0], A[Nbr-1,0]]).reshape(1,2) + A2=np.array([A[0,1], A[Nbr-1,1]]).reshape(1,2) + draw_node_circles(A1, A2, color=node_color, + filled=False, marker_type=node_style) - linecolour=1 -> black elementcolour=1 -> black - 2 -> blue 2 -> blue - 3 -> magenta 3 -> magenta - 4 -> red 4 -> red - sfac = [scalar] scale factor for section force diagrams. +def secforce2(ex, ey, es, plotpar=[2, 1], sfac=None, eci=None): + """ + secforce2(ex,ey,es,plotpar,sfac) + secforce2(ex,ey,es,plotpar,sfac,eci) + [sfac]=secforce2(ex,ey,es) + [sfac]=secforce2(ex,ey,es,plotpar) +-------------------------------------------------------------------------- + PURPOSE: + Draw section force diagram for a two dimensional bar or beam element. + + INPUT: ex = [ x1 x2 ] + ey = [ y1 y2 ] element node coordinates. + + es = [ S1; + S2; + ... ] vector containing the section force + in Nbr evaluation points along the element. + + plotpar=[linecolour, elementcolour] + + linecolour=1 -> black elementcolour=1 -> black + 2 -> blue 2 -> blue + 3 -> magenta 3 -> magenta + 4 -> red 4 -> red + + sfac = [scalar] scale factor for section force diagrams. + + eci = [ x1; + x2; + ... ] local x-coordinates of the evaluation points (Nbr). + If not given, the evaluation points are assumed to be uniformly + distributed +-------------------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2019-12-16 + O Dahlblom 2023-01-31 (Python) - eci = [ x1; - x2; - ... ] local x-coordinates of the evaluation points (Nbr). - If not given, the evaluation points are assumed to be uniformly - distributed + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University +-------------------------------------------------------------------------- """ + if ex.shape != ey.shape: + raise ValueError("Check size of ex, ey dimensions.") - if ex.shape == ey.shape: - if ex.ndim !=1: - nen = ex.shape[1] - else: - nen = ex.shape[0] + c=len(es) + Nbr=c - ex = ex.reshape(1, nen) - ey = ey.reshape(1, nen) - else: - raise ValueError("Check size of ex, ey dimensions.") + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + nxX=dx/L + nyX=dy/L + n = np.array([nxX, nyX]) - #bar2s returns a float - convert it to array - if isinstance(es, float): - es = np.array([es,es]).reshape(2,1) + if sfac is None: + sfac=(0.2*L)/max(abs(es)) - Nbr = es.shape[0] - b = np.array([ex[0,1]-ex[0,0],ey[0,1]-ey[0,0]]) - Length = np.sqrt(b@b) - n = (b/Length).reshape(1,len(b)) + if eci is None: + eci = np.arange(0., L+L/(Nbr-1), L/(Nbr-1)).reshape(Nbr,1) - if plotpar is None: - mpl_diagram_color = (0, 0, 1) # 'b' - mpl_elem_color = (0, 0, 0) # 'k' - elif len(plotpar) != 2: - raise ValueError('Check size of "plotpar" input argument!') + p1 = plotpar[0] + if p1 == 1: + line_color = (0, 0, 0) + elif p1 == 2: + line_color = (0, 0, 1) + elif p1 == 3: + line_color = (1, 0, 1) + elif p1 == 4: + line_color = (1, 0, 0) else: - p1, p2 = plotpar - if p1 == 1: - mpl_diagram_color = (0, 0, 0) # 'k' - elif p1 == 2: - mpl_diagram_color = (0, 0, 1) # 'b' - elif p1 == 3: - mpl_diagram_color = (1, 0, 1) # 'm' - elif p1 == 4: - mpl_diagram_color = (1, 0, 0) # 'r' - - if p2 == 1: - mpl_elem_color = (0, 0, 0) # 'k' - elif p2 == 2: - mpl_elem_color = (0, 0, 1) # 'b' - elif p2 == 3: - mpl_elem_color = (1, 0, 1) # 'm' - elif p2 == 4: - mpl_elem_color = (1, 0, 0) # 'r' - + raise ValueError("Invalid value for plotpar[1].") + line_style = 'solid' - if sfac is None: - sfac=(0.2*Length)/np.max(np.abs(es)) + p2 = plotpar[1] + if p2 == 1: + line_color1 = (0, 0, 0) + elif p2 == 2: + line_color1 = (0, 0, 1) + elif p2 == 3: + line_color1 = (1, 0, 1) + elif p2 == 4: + line_color1 = (1, 0, 0) + else: + raise ValueError("Invalid value for plotpar[1].") - if eci is None: - eci = np.linspace(0,Length,Nbr).reshape(Nbr,1) + a = len(eci) + if a != c: + raise ValueError("Check size of eci dimension.") + + es=es*sfac + +# From local x-coordinates to global coordinates of the element + A = np.zeros(2*Nbr).reshape(Nbr,2) + A[0,0] = ex[0] + A[0,1] = ey[0] + for i in range(Nbr): + A[i,0] = A[0,0]+eci[i]*n[0] + A[i,1] = A[0,1]+eci[i]*n[1] + + B=np.array(A) + +# Plot diagram + for i in range(0, Nbr): + A[i,0]=A[i,0]+es[i]*n[1] + A[i,1]=A[i,1]-es[i]*n[0] + + xc=np.array(A[:,0]) + yc=np.array(A[:,1]) + + plt.plot(xc,yc, color=line_color, linewidth=1) + +# Plot stripes in diagram + xs = np.zeros(2) + ys = np.zeros(2) + for i in range(Nbr): + xs[0]=B[i,0] + xs[1]=A[i,0] + ys[0]=B[i,1] + ys[1]=A[i,1] + print("i,xs,ys=") + print(i,xs,ys) + plt.plot(xs,ys, color=line_color, linewidth=1) +# Plot element + plt.plot(ex,ey, color=line_color1, linewidth=2) + + +def scalgraph2(sfac, magnitude, plotpar=2): + """ + scalgraph2(sfac, magnitude, plotpar) + scalgraph2(sfac, magnitude) + ------------------------------------------------------------- + PURPOSE + Draw a graphic scale - if es.shape[0] != eci.shape[0]: - raise ValueError("Check size of 'es' or 'eci' input argument!") + INPUT: sfac = [scalar] scale factor. - es *= sfac + magnitude = [Ref x y] The graphic scale has a length equivalent + to Ref and starts at coordinates (x,y). + If no coordinates are given the starting + point will be (0,-0.5). - # From local x-coordinates to global coordinates of the element - A = np.zeros([Nbr,2]) - A = [ex[0][0], ey[0][0]] + eci@n - Ax = np.zeros([Nbr-1,2]) - Ax[:,0] = A[:-1,0] - Ax[:,1] = A[1:,0] - Ay = np.zeros([Nbr-1,2]) - Ay[:,0] = A[:-1,1] - Ay[:,1] = A[1:,1] + plotpar=[linecolor] + linecolor=1 -> black + 2 -> blue + 3 -> magenta + 4 -> red + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2015-12-02 + O Dahlblom 2023-01-23 (Python) - Bx=np.copy(Ax) - By=np.copy(Ay) - for i in range(Nbr-1): - Ax[i,:] = [ Ax[i,0]+es[i]*n[0,1], Ax[i,1]+es[i+1]*n[0,1] ] - Ay[i,:] = [ Ay[i,0]-es[i]*n[0,0], Ay[i,1]-es[i+1]*n[0,0] ] + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + cols = len(magnitude) + if cols != 1 and cols != 3 : + raise ValueError("Check size of magnitude input argument.") + if cols == 1 : + N = magnitude + x = 0 + y = -0.5 + if cols == 3 : + N, x, y = magnitude + + print("x= y=") + print(x,y) + + L = N*sfac + print("L=") + print(L) + print("plotpar") + print(plotpar) + + if plotpar == 1: + line_color = (0, 0, 0) + elif plotpar == 2: + line_color = (0, 0, 1) + elif plotpar == 3: + line_color = (1, 0, 1) + elif plotpar == 4: + line_color = (1, 0, 0) + else: + raise ValueError("Invalid value for plotpar[1].") + print("x=") + print(x) + plt.plot([x, (x+L)],[y, y], color=line_color, linewidth=1) + plt.plot([x, x],[(y-L/20), (y+L/20)], color=line_color, linewidth=1) + plt.plot([(x+L), (x+L)],[(y-L/20), (y+L/20)], color=line_color, linewidth=1) + plt.text(x+L*1.1, (y-L/20), str(N)) - #plot diagram and its vertical stripes at the ends - plt.axis('equal') - draw_elements(Ax, Ay, color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - draw_elements(np.array([ex[0][0], Ax[0,0]]).reshape(1,2), np.array([ey[0][0], Ay[0,0]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - draw_elements(np.array([ex[0][1], Ax[-1,-1]]).reshape(1,2), np.array([ey[0][1], Ay[-1,-1]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - #plot stripes in diagram - for i in range(0,Nbr-2): - np.array([Bx[i,1], Ax[i,1]]).reshape(1,2), np.array([By[i,1], Ay[i,1]]).reshape(1,2) - draw_elements(np.array([Bx[i,1], Ax[i,1]]).reshape(1,2), np.array([By[i,1], Ay[i,1]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - #plot elements - draw_elements(ex, ey, color=mpl_elem_color, - line_style='solid', filled=False, closed=False) diff --git a/calfem/vis_vedo.py b/calfem/vis_vedo.py index 2f27b31..cd76fe4 100644 --- a/calfem/vis_vedo.py +++ b/calfem/vis_vedo.py @@ -16,7 +16,7 @@ import time from scipy.io import loadmat import calfem.core as cfc -import vis_vedo_utils as vdu +import calfem.vis_vedo_utils as vdu import vtk # Examples using this module: diff --git a/calfem_python_small.egg-info/PKG-INFO b/calfem_python_small.egg-info/PKG-INFO new file mode 100644 index 0000000..073c99c --- /dev/null +++ b/calfem_python_small.egg-info/PKG-INFO @@ -0,0 +1,22 @@ +Metadata-Version: 2.1 +Name: calfem-python-small +Version: 3.6.3 +Summary: CALFEM for Python +Home-page: https://github.com/CALFEM/calfem-python +Author: Jonas Lindemann, et al +Author-email: jonas.lindemann@byggmek.lth.se +License: MIT +Keywords: finite element,math,numerics +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Build Tools +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.9 +License-File: LICENSE +License-File: LICENSE.txt + +The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s. diff --git a/calfem_python_small.egg-info/SOURCES.txt b/calfem_python_small.egg-info/SOURCES.txt new file mode 100644 index 0000000..8342635 --- /dev/null +++ b/calfem_python_small.egg-info/SOURCES.txt @@ -0,0 +1,108 @@ +LICENSE +LICENSE.txt +MANIFEST.in +README.md +README.rst +setup.py +calfem/__init__.py +calfem/_export.py +calfem/classes_qt4.py +calfem/classes_wx.py +calfem/core.py +calfem/editor.py +calfem/editor_resources.py +calfem/editor_scene.py +calfem/editor_ui.py +calfem/experimental.py +calfem/geometry.py +calfem/intvis.py +calfem/mesh.py +calfem/misc.py +calfem/qt5.py +calfem/shapes.py +calfem/solver.py +calfem/ui.py +calfem/utils.py +calfem/vedo_utils.py +calfem/vis.py +calfem/vis_mpl.py +calfem/vis_vedo.py +calfem/vis_vedo_utils.py +calfem/vis_vtk.py +calfem_python_small.egg-info/PKG-INFO +calfem_python_small.egg-info/SOURCES.txt +calfem_python_small.egg-info/dependency_links.txt +calfem_python_small.egg-info/requires.txt +calfem_python_small.egg-info/top_level.txt +examples/ex_beam2.py +examples/ex_tutorial_1.py +examples/ex_tutorial_2.py +examples/exe_stress_2d_editor.py +examples/exm_circle_bsplines.py +examples/exm_flow_model.py +examples/exm_geometry.py +examples/exm_qt_app.py +examples/exm_qt_app.ui +examples/exm_qt_vis.py +examples/exm_qt_vis.ui +examples/exm_stress_2d.py +examples/exm_stress_2d_export.py +examples/exm_stress_2d_materials.py +examples/exm_stress_2d_pyvtk.py +examples/exm_stress_2d_qt.py +examples/exm_stress_2d_qt.ui +examples/exm_structured_mesh.py +examples/exm_structured_mesh_3d.py +examples/exm_structured_mesh_vtk.py +examples/exm_temp_2d_markers.py +examples/exm_temp_2d_splines_arcs.py +examples/exm_tet_mesh.py +examples/exm_tet_mesh_vtk.py +examples/exs1.py +examples/exs_bar2.py +examples/exs_bar2_la.py +examples/exs_beam1.py +examples/exs_beambar2.py +examples/exs_flw_diff2.py +examples/exs_flw_temp2.py +examples/exs_spring.py +examples/exv1.py +examples/exv2.py +examples/exv3.py +examples/exv4.m +examples/exv4.mat +examples/exv4.py +examples/exv5.py +examples/exvis_beam_soli8.py +examples/.ipynb_checkpoints/Untitled-checkpoint.ipynb +examples/.ipynb_checkpoints/exs1-checkpoint.ipynb +examples/.ipynb_checkpoints/exs2-checkpoint.ipynb +examples/.ipynb_checkpoints/exs3-checkpoint.ipynb +examples/experimental/exed1.py +examples/experimental/exed1.ui +examples/experimental/exint1.py +examples/experimental/exm11.py +examples/experimental/exm11_mpl.py +examples/experimental/exm12.ipynb +examples/experimental/exm12.py +examples/experimental/exm12_mpl.py +examples/experimental/exm14_vtk.py +examples/experimental/exm1_mpl_edit.py +examples/experimental/exs6_test.py +examples/experimental/exui1.py +examples/experimental/gmsh_api_test.py +examples/experimental/gmsh_api_test_2.py +examples/experimental/path_int.py +examples/experimental/plot_test.py +examples/experimental/prim3d.py +examples/experimental/qt1.py +examples/experimental/qt2.py +examples/experimental/test_point_in_geom.py +examples/experimental/test_tri_mesh.py +examples/experimental/.vscode/settings.json +examples/gmsh-api/exgm1.py +examples/gmsh-api/exgm2.py +examples/gmsh-api/exgm3.py +examples/gmsh-api/exgm4.py +examples/obsolete/extri1.py +examples/obsolete/extri2.py \ No newline at end of file diff --git a/calfem_python_small.egg-info/dependency_links.txt b/calfem_python_small.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/calfem_python_small.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/calfem_python_small.egg-info/requires.txt b/calfem_python_small.egg-info/requires.txt new file mode 100644 index 0000000..8b8cb09 --- /dev/null +++ b/calfem_python_small.egg-info/requires.txt @@ -0,0 +1,6 @@ +numpy +visvis +matplotlib +scipy +gmsh +tabulate diff --git a/calfem_python_small.egg-info/top_level.txt b/calfem_python_small.egg-info/top_level.txt new file mode 100644 index 0000000..5fdf479 --- /dev/null +++ b/calfem_python_small.egg-info/top_level.txt @@ -0,0 +1 @@ +calfem diff --git a/examples/exd_beam2_b.py b/examples/exd_beam2_b.py new file mode 100644 index 0000000..71dac27 --- /dev/null +++ b/examples/exd_beam2_b.py @@ -0,0 +1,80 @@ +# example exd_beam2_b +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, time dependent +# boundary conditions. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 + +# ----- Boundary condition, initial condition -------------------- +G = np.array([ + [0, 0], + [0.1, 0.02], + [0.2, -0.01], + [0.3, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) + +bc = np.zeros((4, 1+len(g))) +bc[0,:] = np.hstack((1,g)) +bc[1,0] = 2 +bc[2,0] = 3 +bc[3,0] = 14 + +a0 = np.zeros((15,1)) +da0 = np.zeros((15,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofs = np.array([1,4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(K,[],M,[],a0,da0,bc,ip,times,dofs) + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,dofhist['a'][0,:], '-') +cfv.plt.plot(t,dofhist['a'][1,:],'--') +cfv.plt.plot(t,dofhist['a'][2,:],'-.') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.02,0.03]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 1st, 4th and 11th degree of freedom") +cfv.text("solid line = bottom, vertical beam, x-direction", [0.2,0.022]) +cfv.text("dashed line = center, vertical beam, x-direction", [0.2,0.017]) +cfv.text("dashed-dotted line = center, horizontal beam, y-direction", [0.2,0.012]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=20) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=20) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 20") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file diff --git a/examples/exd_beam2_m.py b/examples/exd_beam2_m.py new file mode 100644 index 0000000..52fb35a --- /dev/null +++ b/examples/exd_beam2_m.py @@ -0,0 +1,104 @@ +# example exd_beam2_m +# ---------------------------------------------------------------- +# PURPOSE +# Set up the fe-model and perform eigenvalue analysis +# for a simple frame structure. +# ---------------------------------------------------------------- + + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + +# ----- Generate the model --------------------------------------- +# ----- Material data -------------------------------------------- +E = 3e10 +Av=0.1030e-2 +Ah=0.0764e-2 +rho=2500 +Iv = 0.0171e-4 +Ih=0.00801e-4 +ep1 = [E, Av, Iv, rho*Av] #IPE100 +ep2 = [E, Ah, Ih, rho*Ah] #IPE80 + +# ----- Topology ------------------------------------------------- +edof = np.array([ + [1,2,3,4,5,6], + [4,5,6,7,8,9], + [7,8,9,10,11,12], + [10,11,12,13,14,15] +]) + +# ----- List of coordinates -------------------------------------- +coord = np.array([ + [0.0, 0.0], + [0.0, 1.5], + [0.0, 3.0], + [1.0, 3.0], + [2.0, 3.0], +]) + +# ----- List of degrees of freedom ------------------------------- +dof = np.array([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12], + [13, 14, 15], +]) + +# ----- Generate element matrices, assemble in global matrices --- +K = np.zeros([15,15]) +M = np.zeros([15,15]) + +ex, ey = cfc.coordxtr(edof, coord, dof); +ep = np.array([ep1, ep1, ep2, ep2]) + +for elx, ely, eltopo, elprop in zip(ex, ey, edof, ep): + Ke, Me = cfc.beam2de(elx, ely, elprop) + cfc.assem(eltopo, K, Ke) + cfc.assem(eltopo, M, Me) + +# ----- Eigenvalue analysis -------------------------------------- +b = np.array([1, 2, 3, 14]) +La, Egv = cfc.eigen(K,M,b) +freq = np.sqrt(La)/(2*np.pi) + +if __name__=='__main__': + # ----- Draw a plot of the element mesh -------------------------- + cfv.figure(1,fig_size=(5.5, 4.5)) + cfv.eldraw2(ex,ey,[1, 2, 1]) + cfv.title('2-D Frame Structure') + + # ----- Plot one eigenmode --------------------------------------- + cfv.figure(2,fig_size=(5.5, 4.5)) + cfv.eldraw2(ex,ey,[2, 3, 1]) + Edb = cfc.extract_ed(edof, Egv[:,0]) + cfv.eldisp2(ex,ey,Edb,[1, 2, 2]) + cfv.title('The first eigenmode') + cfv.text(f"{freq[0]:.2f}", [0.5,1.75]) + ax = cfv.gca() + ax.grid() + + # ----- Plot eight eigenmodes ------------------------------------ + cfv.figure(3,fig_size=(7,5)) + for i in range(4): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+i*3 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*i+0.5,1.5]) + eyt = ey-4 + for i in range(4,8): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+(i-4)*3 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*(i-4)+0.5,-2.5]) + cfv.title("The first eight eigenmodes [Hz]") + ax = cfv.gca() + ax.set_axis_off() + cfv.showAndWait() + +# ----- End ------------------------------------------------------- + diff --git a/examples/exd_beam2_t.py b/examples/exd_beam2_t.py new file mode 100644 index 0000000..6bac640 --- /dev/null +++ b/examples/exd_beam2_t.py @@ -0,0 +1,80 @@ +# example exd_beam2_t +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, full system. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 + +# ----- The load ------------------------------------------------- +G = np.array([ + [0, 0], + [0.15, 1], + [0.25, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) +f = np.zeros((15, len(g))) +f[3,:] = 1000*g + +# ----- Boundary condition, initial condition -------------------- +bc = np.array([ + [1, 0], + [2, 0], + [3, 0], + [14, 0] +]) + +a0 = np.zeros((15,1)) +da0 = np.zeros((15,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofs = np.array([4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(K,[],M,f,a0,da0,bc,ip,times,dofs) + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,dofhist['a'][0,:], '-') +cfv.plt.plot(t,dofhist['a'][1,:],'--') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.01,0.02]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") +cfv.text("solid line = impact point, x-direction", [0.3,0.017]) +cfv.text("dashed line = center, horizontal beam, y-direction", [0.3,0.012]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 25") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file diff --git a/examples/exd_beam2_tr.py b/examples/exd_beam2_tr.py new file mode 100644 index 0000000..0dd929f --- /dev/null +++ b/examples/exd_beam2_tr.py @@ -0,0 +1,85 @@ +# example exd_beam2_tr +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, reduced system. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 +nev = 2 + +# ----- The load ------------------------------------------------- +G = np.array([ + [0, 0], + [0.15, 1], + [0.25, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) +f = np.zeros((15, len(g))) +f[3,:] = 1000*g +fr = np.hstack((np.arange(1,nev+1).reshape(-1,1),Egv[:,:nev].T@f)) + +# ----- Reduced system matrices ---------------------------------- +kr = np.diag(np.diag(Egv[:,:nev].T@K@Egv[:,:nev])) +mr = np.diag(np.diag(Egv[:,:nev].T@M@Egv[:,:nev])) + +# ----- Initial condition ---------------------------------------- +ar0 = np.zeros((nev,1)) +dar0 = np.zeros((nev,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofsr = np.arange(1,nev+1) +dofs = np.array([4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(kr,[],mr,fr,ar0,dar0,[],ip,times,dofsr) + +# ----- Mapping back to original coordinate system --------------- +aR = Egv[:,:nev]@sol['a'] +aRhist = Egv[dofs-1,:nev]@dofhist['a'] + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,aRhist[0,:], '-') +cfv.plt.plot(t,aRhist[1,:],'--') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.01,0.02]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") +cfv.text("solid line = impact point, x-direction", [0.3,0.017]) +cfv.text("dashed line = center, horizontal beam, y-direction", [0.3,0.012]) +cfv.text("TWO EIGENVECTORS ARE USED", [0.3,-0.007]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,aR[:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,aR[:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 25") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file diff --git a/examples/exn_bar2g.py b/examples/exn_bar2g.py new file mode 100644 index 0000000..629250e --- /dev/null +++ b/examples/exn_bar2g.py @@ -0,0 +1,67 @@ +# example exn_bar2g +#-------------------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss using second order theory. +#-------------------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology ----- + +edof = np.array([[1, 2, 5, 6], + [3, 4, 5, 6]]) + +# ----- Element properties and global coordinates ------------------------- + +E=10e9 +A1=4e-2 +A2=1e-2 +ep1=np.array([E, A1]) +ep2=np.array([E, A2]) + +ex1=np.array([0., 1.6]) +ey1=np.array([0., 0.]) +ex2=np.array([0., 1.6]) +ey2=np.array([1.2, 0]) + +# ----- Initial values for the iteration ---------------------------------- + +eps=1e-6 # Error norm +QX1=0.01 +QX2=0; # Initial axial forces +QX01=1 # Axial force of the initial former iteration +n=0 # Iteration counter + +# ----- Iteration procedure ----------------------------------------------- +while abs((QX1-QX01)/QX01) > eps: + n += 1 + + K = np.zeros((6,6)) + f = np.zeros((6,1)) + f[4] = -10e6 + f[5] = -0.2e6 + + Ke1 = cfc.bar2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.bar2ge(ex2,ey2,ep2,QX2) + K = cfc.assem(edof[0,:],K,Ke1) + K=cfc.assem(edof[1,:],K,Ke2) + bc = np.array([1,2,3,4]) + a, r = cfc.solveq(K,f,bc) + + Ed = cfc.extract_ed(edof,a) + + QX01 = QX1 + es1, QX1 = cfc.bar2gs(ex1,ey1,ep1,Ed[0,:]) + es2, QX2 = cfc.bar2gs(ex2,ey2,ep2,Ed[1,:]) + + if n>20: + print("The solution does not converge") + break + +# ----- Results ----------------------------------------------- +print("Displacements:") +print(a) +print("Normal forces:") +print(QX1) +print(QX2) \ No newline at end of file diff --git a/examples/exn_bar2m.py b/examples/exn_bar2m.py new file mode 100644 index 0000000..f9a5082 --- /dev/null +++ b/examples/exn_bar2m.py @@ -0,0 +1,101 @@ +# example exn_bar2m +#-------------------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss considering material nonlinearity. +#-------------------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + +edof = np.array([ + [1, 2, 5, 6], + [5, 6, 7, 8], + [3, 4, 5, 6] +]) + +bc = np.array([1, 2, 3, 4, 7, 8]) + +ex = np.array([ + [0., 1.6], + [1.6, 1.6], + [0., 1.6] +]) + +ey = np.array([ + [0., 0.], + [0., 1.2], + [1.2, 0.] +]) + +E = np.array([200e9, 200e9, 200e9]) +A = np.array([6.0e-4, 3.0e-4, 10.0e-4]) +SY = 400e6 +Ns = (SY*A).reshape(-1,1) + +dp = 4e3 + +incr = 100 + +a = np.zeros((8,1)) +r = np.zeros((8,1)) +es = np.zeros((3,1)) + +plbar = 0 +pl = np.array([0., 0.]) + +# Forward Euler increamental solution + +for i in range(incr): + K = np.zeros((8,8)) + df = np.zeros((8,1)) + df[5] = -dp + + # Create and assemble element tangent stiffness matrix + for j in range(3): + ep = np.array([E[j], A[j]]) + Ke = cfc.bar2e(ex[j,:],ey[j,:],ep) + K = cfc.assem(edof[j,:], K, Ke) + + # Stop iteration if determinant det(Kr) <= 0 + fdof = np.setdiff1d(np.arange(1,9),bc) - 1 + Kr = K[np.ix_(fdof,fdof)] + if np.linalg.det(Kr) <= 0: + print("Determinant zero after increment ", i) + break + + # Solve for the displacement increment and determine total displacements + da, dr = cfc.solveq(K,df,bc) + a += da + r += dr + + # Determine normal forces in elements + ded = cfc.extract_ed(edof,da) + des = np.zeros((3,1)) + for j in range(3): + ep = np.array([E[j], A[j]]) + desj = cfc.bar2s(ex[j,:],ey[j,:],ep,ded[j,:]) + print('---') + print(desj) + print('---') + des[j,0] = desj[0] + es += des + for j in range(3): + if abs(es[j,0]) >= Ns[j]: + E[j] = 0 + + # Determine if the stress in a bar has reached the yield stress + newplbar = np.sum(abs(es)>Ns) + if newplbar > plbar: + plbar = newplbar + print(plbar, "plastic elements for increment ", i+1, " at load = ", (i+1)*dp) + + # Save variables for curve plotting + pl = np.vstack((pl, np.array([-a[5,0], (i+1)*dp]))) + +# Plot force-displacement relation +cfv.figure(1, fig_size=(7,4)) +cfv.plt.plot(pl[:,0],pl[:,1]) +cfv.plt.xlabel("Displacement") +cfv.plt.ylabel("Force") +cfv.showAndWait() \ No newline at end of file diff --git a/examples/exn_beam2.py b/examples/exn_beam2.py new file mode 100644 index 0000000..6650870 --- /dev/null +++ b/examples/exn_beam2.py @@ -0,0 +1,148 @@ +# example exn_beam2g +# ---------------------------------------------------------------- +# PURPOSE +# Geometrically nonlinear analysis of a plane frame. +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + + +#----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +#----- Element stiffness and element load matrices ------------- + +E=200e9 +A1=2e-3 +A2=6e-3 +I1=1.6e-5 +I2=5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) + +ex1 = np.array([0.,0.]) +ey1 = np.array([4.,0.]) +ex2 = np.array([6.,6.]) +ey2 = np.array([4.,0.]) +ex3 = np.array([0.,6.]) +ey3 = np.array([4.,4.]) + +eq1 = np.array([0.]) +eq2 = np.array([0.]) +eq3 = np.array([-50e3]) + +# ----- Initial axial forces ---------------------------------------------- + +QX1 = 1e-4 +QX2 = 0 +QX3 = 0 +QX01 = 1 + +# ----- Iteration for convergence ----------------------------------------- + +eps = 1e-6 +n=0 + +while abs((QX1-QX01)/QX01) > eps: + n += 1 + K = np.zeros([12,12]) + f = np.zeros([12,1]) + f[3,0] = 10e3 + + Ke1 = cfc.beam2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2ge(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2ge(ex3,ey3,ep3,QX3,eq3) + + K = cfc.assem(edof[0,:],K,Ke1) + K = cfc.assem(edof[1,:],K,Ke2) + K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) + + bc = np.array([1, 2, 3, 10, 11]) + a, r = cfc.solveq(K, f, bc) + + ed = cfc.extract_ed(edof,a) + + QX01=QX1 + es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) + es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) + es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) + QX1 = es1[1] + QX2 = es2[1] + QX3 = es3[1] + + if n==1: + ed0 = ed + + if n>20: + print("The solution does not converge") + break + + +# #----- Section forces --------------------------------------- + +eq1 = np.array([0.,eq1.item()]) +eq2 = np.array([0.,eq2.item()]) +eq3 = np.array([0.,eq3.item()]) +es1, edi1, eci1 = cfc.beam2s(ex1,ey1,ep1,ed[0,:],eq1,21) +es2, edi2, eci2 = cfc.beam2s(ex2,ey2,ep1,ed[1,:],eq2,21) +es3, edi3, eci3 = cfc.beam2s(ex3,ey3,ep3,ed[2,:],eq3,21) + + +#----- Draw deformed frame --------------------------------------- +cfv.figure(1,fig_size=(6,4)) +plotpar=[3,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac=cfv.scalfact2(ex3,ey3,edi3,0.1) +plotpar=[1,2,1] +cfv.eldisp2(ex1,ey1,ed[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed[2,:],plotpar,sfac) +plotpar=[2,4,2] +cfv.eldisp2(ex1,ey1,ed0[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed0[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed0[2,:],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Displacements") + + +#----- Draw normal force diagram -------------------------------- +cfv.figure(2,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex1,ey1,es1[:,0],0.2) +cfv.secforce2(ex1,ey1,es1[:,0],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,0],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,0],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Normal force") + +#----- Draw shear force diagram --------------------------------- +cfv.figure(3,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,1],0.2) +cfv.secforce2(ex1,ey1,es1[:,1],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,1],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,1],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Shear force") + +#----- Draw moment diagram -------------------------------------- +cfv.figure(4,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,2],0.2) +cfv.secforce2(ex1,ey1,es1[:,2],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,2],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,2],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Bending moment") +cfv.showAndWait() +#------------------------ end ----------------------------------- \ No newline at end of file diff --git a/examples/exn_beam2_b.py b/examples/exn_beam2_b.py new file mode 100644 index 0000000..0db602b --- /dev/null +++ b/examples/exn_beam2_b.py @@ -0,0 +1,113 @@ +# example exn_beam2g_b +# ---------------------------------------------------------------- +# PURPOSE +# Buckling analysis of a plane frame. +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + + +#----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +#----- Element stiffness and element load matrices ------------- + +E=200e9 +A1=2e-3 +A2=6e-3 +I1=1.6e-5 +I2=5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) + +ex1 = np.array([0.,0.]) +ey1 = np.array([4.,0.]) +ex2 = np.array([6.,6.]) +ey2 = np.array([4.,0.]) +ex3 = np.array([0.,6.]) +ey3 = np.array([4.,4.]) + +eq1 = np.array([0.]) +eq2 = np.array([0.]) +eq3 = np.array([-50e3]) + +# ----- Initial axial forces ---------------------------------------------- + +QX1 = 1e-4 +QX2 = 0 +QX3 = 0 +QX01 = 1 + +# ----- Iteration for convergence ----------------------------------------- + +eps = 1e-6 +n=0 + +while abs((QX1-QX01)/QX01) > eps: + n += 1 + K = np.zeros([12,12]) + f = np.zeros([12,1]) + f[3,0] = 10e3 + + Ke1 = cfc.beam2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2ge(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2ge(ex3,ey3,ep3,QX3,eq3) + + K = cfc.assem(edof[0,:],K,Ke1) + K = cfc.assem(edof[1,:],K,Ke2) + K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) + if n==1: + K0 = K + + bc = np.array([1, 2, 3, 10, 11]) + a, r = cfc.solveq(K, f, bc) + + ed = cfc.extract_ed(edof,a) + + QX01=QX1 + es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) + es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) + es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) + + QX1 = es1[1] + QX2 = es2[1] + QX3 = es3[1] + + if n>20: + print("The solution does not converge") + break + + +# ----- Buckling analysis ------------------------------------------------- + +lam, phi = cfc.eigen(K,K0,bc) +one = np.ones(lam.shape) +alpha = np.divide(one,one-lam) +print(alpha[0]) + +# ----- Draw shape at instability ----------------------------------------- + +Ed = cfc.extract_ed(edof,-phi[:,0]) +cfv.figure(1,fig_size=(6,4)) +plotpar=[3,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac=cfv.scalfact2(ex3,ey3,Ed[2,:],0.1) +plotpar=[1,2,1] +cfv.eldisp2(ex1,ey1,Ed[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,Ed[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,Ed[2,:],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Shape at instability") +cfv.showAndWait() + +#------------------------ end ----------------------------------- \ No newline at end of file diff --git a/examples/exs_bar2.py b/examples/exs_bar2.py index e332348..c1d1e20 100644 --- a/examples/exs_bar2.py +++ b/examples/exs_bar2.py @@ -9,10 +9,12 @@ # REFERENCES # Ola Dahlblom 2004-09-07 # Jonas Lindemann 2009-01-25 +# Ola Dahlblom 2023-02-02 # ---------------------------------------------------------------- import numpy as np import calfem.core as cfc +import calfem.vis_mpl as cfv # ----- Topology matrix Edof ------------------------------------- @@ -83,6 +85,44 @@ ed3 = cfc.extract_ed(edof[2, :], a) N3 = cfc.bar2s(ex3, ey3, ep3, ed3) -print("N1 = "+str(N1)) -print("N2 = "+str(N2)) -print("N3 = "+str(N3)) +print("N1 = ") +print(N1) +print("N2 = ") +print(N2) +print("N3 = ") +print(N3) + +# ----- Draw deformed frame --------------------------------------- + +plotpar = [2, 1, 0] +sfac = cfv.scalfact2(ex3, ey3, ed1, 0.1) +print("sfac=") +print(sfac) + +cfv.figure(1) +cfv.eldraw2(ex1, ey1, plotpar) +cfv.eldraw2(ex2, ey2, plotpar) +cfv.eldraw2(ex3, ey3, plotpar) + +plotpar = [1, 2, 1] +cfv.eldisp2(ex1, ey1, ed1, plotpar, sfac) +cfv.eldisp2(ex2, ey2, ed2, plotpar, sfac) +cfv.eldisp2(ex3, ey3, ed3, plotpar, sfac) +cfv.axis([-0.4, 2.0, -0.4, 1.4]) +plotpar1 = 2 +cfv.scalgraph2(sfac,[1e-3, 0, -0.3],plotpar1) +cfv.title('Displacements') + +# ----- Draw normal force diagram -------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex1, ey1, N2[:,0], 0.1) +cfv.figure(2) +cfv.secforce2(ex1, ey1, N1[:,0], plotpar, sfac) +cfv.secforce2(ex2, ey2, N2[:,0], plotpar, sfac) +cfv.secforce2(ex3, ey3, N3[:,0], plotpar, sfac) +cfv.axis([-0.4, 2.0, -0.4, 1.4]) +cfv.scalgraph2(sfac,[5e4, 0, -0.3],plotpar1) +cfv.title('Normal force') + +cfv.showAndWait() diff --git a/examples/exs_bar2_la.py b/examples/exs_bar2_la.py index a1ef884..a774b0f 100644 --- a/examples/exs_bar2_la.py +++ b/examples/exs_bar2_la.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# example exs4a +# example exs_bar2_la # ---------------------------------------------------------------- # PURPOSE # Analysis of a plane truss using loops. @@ -11,6 +11,7 @@ # K-G Olsson 1995-09-28 # O Dahlblom 2004-08-31 # J Lindemann 2009-01-25 +# O Dahlblom 2023-02-02 # ---------------------------------------------------------------- import numpy as np @@ -101,6 +102,8 @@ i = 0 for elx, ely, eld in zip(ex, ey, ed): - N[i] = cfc.bar2s(elx, ely, ep, eld) + es = cfc.bar2s(elx, ely, ep, eld) + N[i] = es[0] print("N%d = %g" % (i+1, N[i])) i += 1 + diff --git a/examples/exs_bar2_lb.py b/examples/exs_bar2_lb.py new file mode 100644 index 0000000..2fb3d3b --- /dev/null +++ b/examples/exs_bar2_lb.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# example exs_bar2_la +# ---------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss using loops and extraction of +# element coordinates from a global coordinate matrix. +# ---------------------------------------------------------------- + +# REFERENCES +# P-E Austrell 1994-03-08 +# K-G Olsson 1995-09-28 +# O Dahlblom 2004-08-31 +# J Lindemann 2009-01-25 +# O Dahlblom 2019-12-16 +# O Dahlblom 2023-02-02 +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology matrix Edof ------------------------------------- + +edof = np.array([ + [1, 2, 5, 6], + [3, 4, 7, 8], + [5, 6, 9, 10], + [7, 8, 11, 12], + [7, 8, 5, 6], + [11, 12, 9, 10], + [3, 4, 5, 6], + [7, 8, 9, 10], + [1, 2, 7, 8], + [5, 6, 11, 12] +]) + +# ----- Stiffness matrix K and load vector f --------------------- + +K = np.zeros([12, 12]) +f = np.zeros([12, 1]) +f[10] = 0.5e6*np.sin(np.pi/6) +f[11] = -0.5e6*np.cos(np.pi/6) + +# ----- Element properties --------------------------------------- + +A = 25.0e-4 +E = 2.1e11 +ep = [E, A] + +#----- Global coordinates and topology -------------------------- + +coord = np.array([ + [0, 2], + [0, 0], + [2, 2], + [2, 0], + [4, 2], + [4, 0] +]) + +dof = np.array([ + [ 1, 2], + [ 3, 4], + [ 5, 6], + [ 7, 8], + [ 9, 10], + [11, 12] +]) + +# ----- Element coordinates -------------------------------------- + +ex, ey = cfc.coordxtr(edof, coord, dof,2) + +# ----- Create element stiffness matrices Ke and assemble into K - + +for elx, ely, eltopo in zip(ex, ey, edof): + Ke = cfc.bar2e(elx, ely, ep) + cfc.assem(eltopo, K, Ke) + +print("Stiffness matrix K:") +print(K) + +# ----- Solve the system of equations ---------------------------- + +bc = np.array([1, 2, 3, 4]) +a, r = cfc.solveq(K, f, bc) + +print("Displacements a:") +print(a) + +print("Reaction forces r:") +print(r) + +# ----- Element forces ------------------------------------------- + +ed = cfc.extract_ed(edof, a) +N = np.zeros([edof.shape[0]]) + +print("Element forces:") + +i = 0 +for elx, ely, eld in zip(ex, ey, ed): + es = cfc.bar2s(elx, ely, ep, eld) + N[i] = es[0] + print("N%d = %g" % (i+1, N[i])) + i += 1 + diff --git a/examples/exs_beam1.py b/examples/exs_beam1.py index 2c557b1..4608101 100644 --- a/examples/exs_beam1.py +++ b/examples/exs_beam1.py @@ -1,80 +1,100 @@ # -*- coding: utf-8 -*- # -# example exs5 -# ---------------------------------------------------------------- -# PURPOSE +# example exs_beam1 +#---------------------------------------------------------------- +# PURPOSE # Analysis of a simply supported beam. -# ---------------------------------------------------------------- +#---------------------------------------------------------------- # REFERENCES -# Göran Sandberg 94-03-08 -# Karl-Gunnar Olsson 95-09-28 -# Ola Dahlblom 2004-09-21 +# Ola Dahlblom 2015-11-13 +# Ola Dahlblom 2019-12-11 +# Ola Dahlblom 2022-07-11 # ---------------------------------------------------------------- import numpy as np +import matplotlib.pyplot as plt import calfem.core as cfc +import calfem.utils as cfu +import calfem.vis_mpl as cfv # ----- Topology ------------------------------------------------- edof = np.array([ - [1, 2, 3, 4, 5, 6], - [4, 5, 6, 7, 8, 9], - [7, 8, 9, 10, 11, 12] + [1, 2, 3, 4], + [3, 4, 5, 6] ]) # ----- Stiffness matrix K and load vector f --------------------- -K = np.mat(np.zeros((12, 12))) -f = np.mat(np.zeros((12, 1))) -f[4] = -10000. +K = np.array(np.zeros((6, 6))) +f = np.array(np.zeros((6, 1))) +f[2] = -10e+3 -# ----- Element stiffness matrices ------------------------------ +# ----- Element stiffness and element load matrices ------------- -E = 2.1e11 -A = 45.3e-4 +E = 210e9 I = 2510e-8 -ep = np.array([E, A, I]) -ex = np.array([0., 3.]) -ey = np.array([0., 0.]) -Ke = cfc.beam2e(ex, ey, ep) +ep = np.array([E, I]) +ex1 = np.array([0, 3]) +ex2 = np.array([3, 9]) +eq1 = np.array([0]) +eq2 = np.array([0]) -print(Ke) +Ke1 = cfc.beam1e(ex1, ep) +Ke2 = cfc.beam1e(ex2, ep) # ----- Assemble Ke into K --------------------------------------- -K = cfc.assem(edof, K, Ke) +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) -# ----- Solve the system of equations and compute support forces - +# ----- Solve the system of equations and compute reactions ------ -bc = np.array([1, 2, 11]) -(a, r) = cfc.solveq(K, f, bc) +bc = np.array([1, 5]) +a, r = cfc.solveq(K, f, bc) + +print("a = ") +print(a) +print("r = ") +print(r) # ----- Section forces ------------------------------------------- ed = cfc.extract_ed(edof, a) -es1, ed1, ec1 = cfc.beam2s(ex, ey, ep, ed[0, :], nep=10) -es2, ed2, ec2 = cfc.beam2s(ex, ey, ep, ed[1, :], nep=10) -es3, ed3, ec3 = cfc.beam2s(ex, ey, ep, ed[2, :], nep=10) - -# ----- Results -------------------------------------------------- +es1, ed1, ec1 = cfc.beam1s(ex1, ep, ed[0, :], eq1, nep=4) +es2, ed2, ec2 = cfc.beam1s(ex2, ep, ed[1, :], eq2, nep=7) -print("a=") -print(a) -print("r=") -print(r) -print("es1=") +print("es1 = ") print(es1) -print("es2=") -print(es2) -print("es3=") -print(es3) - -print("ed1=") +print("ed1 = ") print(ed1) -print("ed2=") +print("es2 = ") +print(es2) +print("ed2 = ") print(ed2) -print("ed3=") -print(ed3) + +#----- Draw deformed beam --------------------------------------- + +cfv.figure(1) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),np.concatenate(([0],ed1[:,0], ed2[:,0],[0]), 0), color=(0.0, 0.0, 0.0)) +cfv.title('displacements') + +#----- Draw shear force diagram---------------------------------- + +cfv.figure(2) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),-np.concatenate(([0],es1[:,0], es2[:,0],[0]), 0)/1000, color=(0.0, 0.0, 0.0)) +cfv.title('shear force') + +#----- Draw moment diagram---------------------------------- + +cfv.figure(3) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),-np.concatenate(([0],es1[:,1], es2[:,1],[0]), 0)/1000, color=(0.0, 0.0, 0.0)) +cfv.title('bending moment') + +cfv.showAndWait() diff --git a/examples/exs_beam2.py b/examples/exs_beam2.py new file mode 100644 index 0000000..ad6594c --- /dev/null +++ b/examples/exs_beam2.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# +# example exs_beam2 +# ---------------------------------------------------------------- +# PURPOSE +# Analysis of a plane frame. +# ---------------------------------------------------------------- + +# REFERENCES +# Göran Sandberg 94-03-08 +# Karl-Gunnar Olsson 95-09-28 +# Anders Olsson 99-03-01 +# Ola Dahlblom 2004-09-14 +# Ola Dahlblom 2019-12-16 +# Ola Dahlblom 2023-02-03 +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.utils as cfu +import calfem.vis_mpl as cfv + +# ----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +# ----- Stiffness matrix K and load vector f --------------------- + +K = np.array(np.zeros((12, 12))) +f = np.array(np.zeros((12, 1))) +f[3] = 2.e+3 + +# ----- Element stiffness and element load matrices ------------- + +E = 200.e9 +A1 = 2.e-3 +A2 = 6.e-3 +I1 = 1.6e-5 +I2 = 5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) +ex1 = np.array([0, 0]) +ex2 = np.array([6, 6]) +ex3 = np.array([0, 6]) +ey1 = np.array([4, 0]) +ey2 = np.array([4, 0]) +ey3 = np.array([4, 4]) +eq1 = np.array([0, 0]) +eq2 = np.array([0, 0]) +eq3 = np.array([0, -10e+3]) + +Ke1 = cfc.beam2e(ex1, ey1, ep1) +Ke2 = cfc.beam2e(ex2, ey2, ep1) +Ke3, fe3 = cfc.beam2e(ex3, ey3, ep3, eq3) + +# ----- Assemble Ke into K --------------------------------------- + +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) +cfc.assem(edof[2, :], K, Ke3, f, fe3) + +# ----- Solve the system of equations and compute reactions ------ + +bc = np.array([1, 2, 3, 10, 11]) +a, r = cfc.solveq(K, f, bc) + +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- + +ed = cfc.extract_ed(edof, a) + +es1, edi1, ec1 = cfc.beam2s(ex1, ey1, ep1, ed[0, :], eq1, nep=21) +es2, edi2, ec2 = cfc.beam2s(ex2, ey2, ep1, ed[1, :], eq2, nep=21) +es3, edi3, ec3 = cfc.beam2s(ex3, ey3, ep3, ed[2, :], eq3, nep=21) + +print("es1 = ") +print(es1) +print("edi1 = ") +print(edi1) +print("es2 = ") +print(es2) +print("edi2 = ") +print(edi2) +print("es3 = ") +print(es3) +print("edi3 = ") +print(edi3) + +# ----- Draw deformed frame --------------------------------------- + +plotpar = [2, 1, 0] +sfac = cfv.scalfact2(ex3, ey3, edi3, 0.1) +print("sfac=") +print(sfac) + +cfv.figure(1) +cfv.eldraw2(ex1, ey1, plotpar) +cfv.eldraw2(ex2, ey2, plotpar) +cfv.eldraw2(ex3, ey3, plotpar) + +plotpar = [1, 2, 1] +cfv.dispbeam2(ex1, ey1, edi1, plotpar, sfac) +cfv.dispbeam2(ex2, ey2, edi2, plotpar, sfac) +cfv.dispbeam2(ex3, ey3, edi3, plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +plotpar1 = 2 +cfv.scalgraph2(sfac,[1e-2, 0.5, 0],plotpar1); +cfv.title('Displacements') + +# ----- Draw normal force diagram -------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex1, ey1, es1[:,0], 0.2) +cfv.figure(2) +cfv.secforce2(ex1, ey1, es1[:,0], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,0], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,0], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 1.5, 0],plotpar1) +cfv.title('Normal force') + +# ----- Draw shear force diagram --------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex3, ey3, es3[:,1], 0.2) +cfv.figure(3) +cfv.secforce2(ex1, ey1, es1[:,1], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,1], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,1], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 0.5, 0],plotpar1) +cfv.title('Shear force') + +# ----- Draw moment diagram -------------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex3, ey3, es3[:,2], 0.2) +print("sfac=") +print(sfac) + +cfv.figure(4) +cfv.secforce2(ex1, ey1, es1[:,2], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,2], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,2], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 0.5, 0],plotpar1) +cfv.title('Moment') + +cfv.showAndWait() \ No newline at end of file diff --git a/examples/exs_beambar2.py b/examples/exs_beambar2.py index 5514923..70633c4 100644 --- a/examples/exs_beambar2.py +++ b/examples/exs_beambar2.py @@ -1,17 +1,18 @@ # -*- coding: utf-8 -*- # -# example exs7 +# example exs_beam2 # ---------------------------------------------------------------- # PURPOSE -# Set up a frame, consisting of both beams and bars, and -# illustrate the calculations by use of graphics functions. +# Analysis of a combined beam and bar structure. # ---------------------------------------------------------------- # REFERENCES -# P-A Hansson 1994-01-20 -# K-G Olsson 1995-09-28 -# O Dahlblom 2004-10-07 -# J Lindemann 2021-12-29 (Python version) +# Ola Dahlblom 2015-11-16 +# Ola Dahlblom 2019-12-19 +# Ola Dahlblom 2023-02-02 +# Copyright (c) Division of Structural Mechanics and +# Division of Solid Mechanics. +# Lund University # ---------------------------------------------------------------- import numpy as np @@ -19,92 +20,93 @@ import calfem.utils as cfu import calfem.vis_mpl as cfv -np.set_printoptions(precision=3, suppress=True) +#np.set_printoptions(precision=3, suppress=True) -# ----- System matrices ------------------------------------------ +# ----- Topology ------------------------------------------------- -K = np.zeros((18, 18)) -f = np.zeros((18, 1)) - -f[12] = 1 - -coord = np.array([ - [0., 0.], - [1., 0.], - [0., 1.], - [1., 1.], - [0., 2.], - [1., 2.] +edof1 = np.array([ + [1, 2, 3, 4, 5, 6], + [4, 5, 6, 7, 8, 9], + [7, 8, 9, 10, 11, 12] ]) -dof = np.array([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [10, 11, 12], - [13, 14, 15], - [16, 17, 18] +edof2 = np.array([ + [13, 14, 4, 5], + [13, 14, 7, 8] ]) -# ----- Element properties, topology and coordinates ------------- +# ----- Stiffness matrix K and load vector f --------------------- -ep1 = [1, 1, 1] -edof1 = np.array([ - [1, 2, 3, 7, 8, 9], - [7, 8, 9, 13, 14, 15], - [4, 5, 6, 10, 11, 12], - [10, 11, 12, 16, 17, 18], - [7, 8, 9, 10, 11, 12], - [13, 14, 15, 16, 17, 18] -]) +K = np.array(np.zeros((14, 14))) +f = np.array(np.zeros((14, 1))) -ex1, ey1 = cfc.coordxtr(edof1, coord, dof, 2) +# ----- Element stiffness and element load matrices ------------- -ep2 = [1, 1] -edof2 = np.array([ - [1, 2, 10, 11], - [7, 8, 16, 17], - [7, 8, 4, 5], - [13, 14, 10, 11] -]) +E = 200.e9 +A1 = 4.e-3 +I1 = 5.4e-5 +A2 = 1.e-3 -ex2, ey2 = cfc.coordxtr(edof2, coord, dof, 2) +ep1 = np.array([E, A1, I1]) +ep4 = np.array([E, A2]) -# ----- Draw the fe-mesh as a check of the model ----------------- +eq1 = np.array([0, 0]) +eq2 = np.array([0, -10e+3]) -cfv.figure(1) -cfv.eldraw2(ex1, ey1, [1, 3, 1]) -cfv.eldraw2(ex2, ey2, [1, 2, 1]) +ex1 = np.array([0, 2]) +ex2 = np.array([2, 4]) +ex3 = np.array([4, 6]) +ex4 = np.array([0, 2]) +ex5 = np.array([0, 4]) +ey1 = np.array([2, 2]) +ey2 = np.array([2, 2]) +ey3 = np.array([2, 2]) +ey4 = np.array([0, 2]) +ey5 = np.array([0, 2]) -# ----- Create and assemble element matrices --------------------- +Ke1 = cfc.beam2e(ex1, ey1, ep1) +Ke2, fe2 = cfc.beam2e(ex2, ey2, ep1, eq2) +Ke3, fe3 = cfc.beam2e(ex3, ey3, ep1, eq2) +Ke4 = cfc.bar2e(ex4, ey4, ep4) +Ke5 = cfc.bar2e(ex5, ey5, ep4) -for elx, ely, eltopo in zip(ex1, ey1, edof1): - Ke = cfc.beam2e(elx, ely, ep1) - K = cfc.assem(eltopo, K, Ke) +# ----- Assemble Ke into K --------------------------------------- -for elx, ely, eltopo in zip(ex2, ey2, edof2): - Ke = cfc.bar2e(elx, ely, ep2) - K = cfc.assem(eltopo, K, Ke) +cfc.assem(edof1[0, :], K, Ke1) +cfc.assem(edof1[1, :], K, Ke2, f, fe2) +cfc.assem(edof1[2, :], K, Ke3, f, fe3) +cfc.assem(edof2[0, :], K, Ke4) +cfc.assem(edof2[1, :], K, Ke5) -# ----- Solve equation system ------------------------------------ +# ----- Solve the system of equations and compute reactions ------ -bc = np.array([1, 2, 3, 4, 5, 6]) +bc = np.array([1, 2, 3, 13, 14]) a, r = cfc.solveq(K, f, bc) -# ---- Extract element displacements and display the deformed mesh - +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- ed1 = cfc.extract_ed(edof1, a) ed2 = cfc.extract_ed(edof2, a) -sfac = cfv.scalfact2(ex1, ey1, ed1, 0.1) - -cfv.figure(2) -cfv.eldraw2(ex1, ey1) -cfv.eldraw2(ex2, ey2) -cfv.eldisp2(ex1, ey1, ed1, [2, 1, 1], sfac) -cfv.eldisp2(ex2, ey2, ed2, [2, 1, 1], sfac) - -cfv.show_and_wait() - +es1, _, _ = cfc.beam2s(ex1, ey1, ep1, ed1[0, :], eq1, nep=11) +es2, _, _ = cfc.beam2s(ex2, ey2, ep1, ed1[1, :], eq2, nep=11) +es3, _, _ = cfc.beam2s(ex3, ey3, ep1, ed1[2, :], eq2, nep=11) +es4 = cfc.bar2s(ex4, ey4, ep4, ed2[0, :]) +es5 = cfc.bar2s(ex5, ey5, ep4, ed2[1, :]) + +print("es1 = ") +print(es1) +print("es2 = ") +print(es2) +print("es3 = ") +print(es3) +print("es4 = ") +print(es4) +print("es5 = ") +print(es5) -# -------------------------- end -------------------------------- diff --git a/examples/exs_flw_temp1.py b/examples/exs_flw_temp1.py new file mode 100644 index 0000000..b92c2e1 --- /dev/null +++ b/examples/exs_flw_temp1.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# +# example exs_flw_temp1 +#---------------------------------------------------------------- +# PURPOSE +# Analysis of one dimensional heat flow. +#---------------------------------------------------------------- + +# REFERENCES +# P-E Austrell 1994-03-08 +# K-G Olsson 1995-09-28 +# O Dahlblom 2004-09-07 +# O Dahlblom 2023-02-02 +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology ------------------------------------------------- + +edof = np.array([ + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 6] +]) + +# ----- Stiffness matrix K and load vector f --------------------- + +K = np.array(np.zeros((6, 6))) +f = np.array(np.zeros((6, 1))) +f[3] = 10 + +# ----- Element stiffness and element load matrices ------------- + +ep1 = 25 +ep2 = 24.3 +ep3 = 0.4 +ep4 = 17 +ep5 = 7.7 + +Ke1 = cfc.spring1e(ep1) +Ke2 = cfc.spring1e(ep2) +Ke3 = cfc.spring1e(ep3) +Ke4 = cfc.spring1e(ep4) +Ke5 = cfc.spring1e(ep5) + +# ----- Assemble Ke into K --------------------------------------- + +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) +cfc.assem(edof[2, :], K, Ke3) +cfc.assem(edof[3, :], K, Ke4) +cfc.assem(edof[4, :], K, Ke5) + +# ----- Solve the system of equations ---------------------------- + +bc = np.array([1, 6]) +bcVal = np.array([-17, 20]) +a, r = cfc.solveq(K, f, bc, bcVal) + +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- + +ed1 = cfc.extract_ed(edof[0, :], a) +ed2 = cfc.extract_ed(edof[1, :], a) +ed3 = cfc.extract_ed(edof[2, :], a) +ed4 = cfc.extract_ed(edof[3, :], a) +ed5 = cfc.extract_ed(edof[4, :], a) + +q1 = cfc.spring1s(ep1, ed1) +q2 = cfc.spring1s(ep2, ed2) +q3 = cfc.spring1s(ep3, ed3) +q4 = cfc.spring1s(ep4, ed4) +q5 = cfc.spring1s(ep5, ed5) + +print("q1 = ") +print(q1) +print("q2 = ") +print(q2) +print("q3 = ") +print(q3) +print("q4 = ") +print(q4) +print("q5 = ") +print(q5) + diff --git a/examples/exv1.py b/examples/exv1.py index 9304a14..d624090 100644 --- a/examples/exv1.py +++ b/examples/exv1.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv coord = np.array([ [0], diff --git a/examples/exv2.py b/examples/exv2.py index 82e2054..b9d4449 100644 --- a/examples/exv2.py +++ b/examples/exv2.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv coord = np.array([ [0, 0, 0], diff --git a/examples/exv3.py b/examples/exv3.py index 879ec77..f0b2f91 100644 --- a/examples/exv3.py +++ b/examples/exv3.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfvv +import calfem.vis_vedo as cfv import calfem.geometry as cfg import calfem.mesh as cfm import calfem.utils as cfu diff --git a/examples/exv4.py b/examples/exv4.py index 1cbf6ec..ac63b9a 100644 --- a/examples/exv4.py +++ b/examples/exv4.py @@ -7,8 +7,8 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv -import calfem.vedo_utils as cfvu +import calfem.vis_vedo as cfvv +import calfem.vis_vedo_utils as cfvu edof,coord,dof,a,ed,bc,f_dofs,Stress_tensors,vM_el,vM_n,lamb,eig = cfvv.import_mat('exv4',['edof','coord','dof','a','ed','bc','force_dofs','Stress_tensors','vM_el','vM_n','lambda','eig']) diff --git a/examples/exv5.py b/examples/exv5.py index 54b32a6..b0ea62a 100644 --- a/examples/exv5.py +++ b/examples/exv5.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv # Adaptation of platre from version 3.4 for MATLAB # This function is not in the Python version currently diff --git a/setup-org.py b/setup-org.py new file mode 100644 index 0000000..2e0f809 --- /dev/null +++ b/setup-org.py @@ -0,0 +1,113 @@ +"""A setuptools based setup module. + +See: +https://github.com/CALFEM/calfem-python +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +from os import path +import os, glob, sys + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +def gen_data_files(*dirs): + results = [] + + for src_dir in dirs: + for root,dirs,files in os.walk(src_dir): + results.append((root, map(lambda f:root + "/" + f, files))) + return results + +setup( + name='calfem-python', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + + version='3.6.3', + + description='CALFEM for Python', + long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', + + # The project's main homepage. + url='https://github.com/CALFEM/calfem-python', + + # Author details + author='Jonas Lindemann, et al', + author_email='jonas.lindemann@byggmek.lth.se', + + # Choose your license + license='MIT', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', + ], + + # What does your project relate to? + keywords='finite element, math, numerics', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + #packages=find_packages(exclude=['contrib', 'docs', 'tests']), + #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), + packages=['calfem',], + + # Alternatively, if you want to distribute just a my_module.py, uncomment + # this: + # py_modules=["my_module"], + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'], + include_package_data=True + #package_data={'calfem': ['examples/*']} + + #data_files=gen_data_files("examples", "doc") + + #package_data={ + # 'calfem': ['examples/*.py', 'examples/*.ui'] + #} + + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # for example: + # $ pip install -e .[dev,test] + #extras_require={ + # 'dev': ['check-manifest'], + # 'test': ['coverage'], + #}, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. +) diff --git a/setup-template.py b/setup-template.py new file mode 100644 index 0000000..1176426 --- /dev/null +++ b/setup-template.py @@ -0,0 +1,96 @@ +"""A setuptools based setup module. + +See: +https://github.com/CALFEM/calfem-python +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +from os import path +import os, glob, sys + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +def gen_data_files(*dirs): + results = [] + + for src_dir in dirs: + for root,dirs,files in os.walk(src_dir): + results.append((root, map(lambda f:root + "/" + f, files))) + return results + +setup( + name='{package_name}', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + + version='{package_version}', + + description='CALFEM for Python', + long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', + + # The project's main homepage. + url='https://github.com/CALFEM/calfem-python', + + # Author details + author='Jonas Lindemann, et al', + author_email='jonas.lindemann@lunarc.lu.se', + + # Choose your license + license='MIT', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', + ], + + # What does your project relate to? + keywords='finite element, math, numerics', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + #packages=find_packages(exclude=['contrib', 'docs', 'tests']), + #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), + packages=['calfem',], + + # Alternatively, if you want to distribute just a my_module.py, uncomment + # this: + # py_modules=["my_module"], + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[{package_depends}], + include_package_data=True + + #data_files=gen_data_files("examples", "doc") + +) diff --git a/setup.py b/setup.py index 6d42204..02102e5 100644 --- a/setup.py +++ b/setup.py @@ -26,13 +26,13 @@ def gen_data_files(*dirs): return results setup( - name='calfem-python', + name='calfem-python-small', # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='3.6.2', + version='3.6.3', description='CALFEM for Python', long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', @@ -68,6 +68,7 @@ def gen_data_files(*dirs): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', ], # What does your project relate to? @@ -87,26 +88,9 @@ def gen_data_files(*dirs): # your project is installed. For an analysis of "install_requires" vs pip's # requirements files see: # https://packaging.python.org/en/latest/requirements.html - install_requires=['numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'], + install_requires=['numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'], include_package_data=True - #package_data={'calfem': ['examples/*']} #data_files=gen_data_files("examples", "doc") - #package_data={ - # 'calfem': ['examples/*.py', 'examples/*.ui'] - #} - - # List additional groups of dependencies here (e.g. development - # dependencies). You can install these using the following syntax, - # for example: - # $ pip install -e .[dev,test] - #extras_require={ - # 'dev': ['check-manifest'], - # 'test': ['coverage'], - #}, - - # If there are data files included in your packages that need to be - # installed, specify them here. If using Python 2.6 or less, then these - # have to be included in MANIFEST.in as well. )