def strainGLO(IELCON, UU, ne, COORD, elements): """Compute the strain solution for all the elements Computes the strain solution for all the elements in the domain and the physical coordinates of the complete domain integration points. It then assembles all the element strains into a global strains vector EG[]. Parameters ---------- IELCON : ndarray (int) Array with the nodes numbers for each element. UU : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. ne : int Number of elements. COORD : ndarray (float). Array with nodes coordinates. elements : ndarray (int) Array with the node number for the nodes that correspond to each element. Returns ------- EG : ndarray (float) Array that contains the strain solution for each integration point in physical coordinates. XS : ndarray (float) Array with the coordinates of the integration points. """ iet = elements[0, 1] ndof, nnodes, ngpts = fe.eletype(iet) XS = np.zeros([ngpts*ne, 2], dtype=np.float) elcoor = np.zeros([nnodes, 2], dtype=np.float) EG = np.zeros([ngpts*ne, 3], dtype=np.float) ul = np.zeros([ndof], dtype=np.float) for i in range(ne): for j in range(nnodes): elcoor[j, 0] = COORD[IELCON[i, j], 0] elcoor[j, 1] = COORD[IELCON[i, j], 1] for j in range(ndof): ul[j] = UU[i, j] if iet == 1: epsG, xl = fe.str_el4(elcoor, ul) elif iet == 2: epsG, xl = fe.str_el6(elcoor, ul) elif iet == 3: epsG, xl = fe.str_el3(elcoor, ul) for j in range(ngpts): XS[ngpts*i + j, 0] = xl[j, 0] XS[ngpts*i + j, 1] = xl[j, 1] for k in range(3): EG[ngpts*i + j, k] = epsG[j, k] return EG, XS
def strainGLO(IELCON, UU, ne, COORD, elements): """Compute the strain solution for all the elements Computes the strain solution for all the elements in the domain and the physical coordinates of the complete domain integration points. It then assembles all the element strains into a global strains vector EG[]. Parameters ---------- IELCON : ndarray (int) Array with the nodes numbers for each element. UU : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. ne : int Number of elements. COORD : ndarray (float). Array with nodes coordinates. elements : ndarray (int) Array with the node number for the nodes that correspond to each element. Returns ------- EG : ndarray (float) Array that contains the strain solution for each integration point in physical coordinates. XS : ndarray (float) Array with the coordinates of the integration points. """ iet = elements[0, 1] ndof, nnodes, ngpts = fe.eletype(iet) XS = np.zeros([ngpts * ne, 2], dtype=np.float) elcoor = np.zeros([nnodes, 2], dtype=np.float) EG = np.zeros([ngpts * ne, 3], dtype=np.float) ul = np.zeros([ndof], dtype=np.float) for i in range(ne): for j in range(nnodes): elcoor[j, 0] = COORD[IELCON[i, j], 0] elcoor[j, 1] = COORD[IELCON[i, j], 1] for j in range(ndof): ul[j] = UU[i, j] if iet == 1: epsG, xl = fe.str_el4(elcoor, ul) elif iet == 2: epsG, xl = fe.str_el6(elcoor, ul) elif iet == 3: epsG, xl = fe.str_el3(elcoor, ul) for j in range(ngpts): XS[ngpts * i + j, 0] = xl[j, 0] XS[ngpts * i + j, 1] = xl[j, 1] for k in range(3): EG[ngpts * i + j, k] = epsG[j, k] return EG, XS
def strain_nodes(IELCON, UU, ne, COORD, elements, mats): """Compute averaged strains and stresses at nodes First, the variable is extrapolated from the Gauss point to nodes for each element. Then, these values are averaged according to the number of element that share that node. The theory for this technique can be found in [1]_. Parameters ---------- IELCON : ndarray (int) Array with the nodes numbers for each element. UU : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. ne : int Number of elements. COORD : ndarray (float). Array with nodes coordinates. elements : ndarray (int) Array with the node number for the nodes that correspond to each element. Returns ------- E_nodes : ndarray Strains evaluated at the nodes. References ---------- .. [1] O.C. Zienkiewicz and J.Z. Zhu, The Superconvergent patch recovery and a posteriori error estimators. Part 1. The recovery technique, Int. J. Numer. Methods Eng., 33, 1331-1364 (1992). """ iet = elements[0, 1] ndof, nnodes, ngpts = fe.eletype(iet) elcoor = np.zeros([nnodes, 2]) E_nodes = np.zeros([COORD.shape[0], 3]) S_nodes = np.zeros([COORD.shape[0], 3]) el_nodes = np.zeros([COORD.shape[0]], dtype=int) ul = np.zeros([ndof]) for i in range(ne): young, poisson = mats[elements[i, 2], :] shear = young/(2*(1 + poisson)) fact1 = young/(1 - poisson**2) fact2 = poisson*young/(1 - poisson**2) for j in range(nnodes): elcoor[j, 0] = COORD[IELCON[i, j], 0] elcoor[j, 1] = COORD[IELCON[i, j], 1] for j in range(ndof): ul[j] = UU[i, j] if iet == 1: epsG, xl = fe.str_el4(elcoor, ul) extrap0 = interp2d(xl[:, 0], xl[:,1], epsG[:, 0]) extrap1 = interp2d(xl[:, 0], xl[:,1], epsG[:, 1]) extrap2 = interp2d(xl[:, 0], xl[:,1], epsG[:, 2]) elif iet == 2: epsG, xl = fe.str_el6(elcoor, ul) extrap0 = interp2d(xl[:, 0], xl[:,1], epsG[:, 0]) extrap1 = interp2d(xl[:, 0], xl[:,1], epsG[:, 1]) extrap2 = interp2d(xl[:, 0], xl[:,1], epsG[:, 2]) elif iet == 3: epsG, xl = fe.str_el3(elcoor, ul) extrap0 = lambda x, y: epsG[0, 0] extrap1 = lambda x, y: epsG[0, 1] extrap2 = lambda x, y: epsG[0, 2] for node in IELCON[i, :]: x, y = COORD[node, :] E_nodes[node, 0] = E_nodes[node, 0] + extrap0(x, y) E_nodes[node, 1] = E_nodes[node, 1] + extrap1(x, y) E_nodes[node, 2] = E_nodes[node, 2] + extrap2(x, y) S_nodes[node, 0] = S_nodes[node, 0] + fact1*extrap0(x, y) \ + fact2*extrap1(x, y) S_nodes[node, 1] = S_nodes[node, 1] + fact2*extrap0(x, y) \ + fact1*extrap1(x, y) S_nodes[node, 2] = S_nodes[node, 2] + shear*extrap2(x, y) el_nodes[node] = el_nodes[node] + 1 E_nodes[:, 0] = E_nodes[:, 0]/el_nodes E_nodes[:, 1] = E_nodes[:, 1]/el_nodes E_nodes[:, 2] = E_nodes[:, 2]/el_nodes S_nodes[:, 0] = S_nodes[:, 0]/el_nodes S_nodes[:, 1] = S_nodes[:, 1]/el_nodes S_nodes[:, 2] = S_nodes[:, 2]/el_nodes return E_nodes, S_nodes
def strain_nodes(nodes, elements, mats, UC): """Compute averaged strains and stresses at nodes First, the variable is extrapolated from the Gauss point to nodes for each element. Then, these values are averaged according to the number of element that share that node. The theory for this technique can be found in [1]_. Parameters ---------- nodes : ndarray (float). Array with nodes coordinates. elements : ndarray (int) Array with the node number for the nodes that correspond to each element. mats : ndarray (float) Array with material profiles. UC : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. Returns ------- E_nodes : ndarray Strains evaluated at the nodes. References ---------- .. [1] O.C. Zienkiewicz and J.Z. Zhu, The Superconvergent patch recovery and a posteriori error estimators. Part 1. The recovery technique, Int. J. Numer. Methods Eng., 33, 1331-1364 (1992). """ ne = elements.shape[0] nn = nodes.shape[0] iet = elements[0, 1] ndof, nnodes, _ = fe.eletype(iet) elcoor = np.zeros([nnodes, 2]) E_nodes = np.zeros([nn, 3]) S_nodes = np.zeros([nn, 3]) el_nodes = np.zeros([nn], dtype=int) ul = np.zeros([ndof]) IELCON = elements[:, 3:] for i in range(ne): young, poisson = mats[np.int(elements[i, 2]), :] shear = young / (2 * (1 + poisson)) fact1 = young / (1 - poisson**2) fact2 = poisson * young / (1 - poisson**2) for j in range(nnodes): elcoor[j, 0] = nodes[IELCON[i, j], 1] elcoor[j, 1] = nodes[IELCON[i, j], 2] ul[2 * j] = UC[IELCON[i, j], 0] ul[2 * j + 1] = UC[IELCON[i, j], 1] if iet == 1: epsG, _ = fe.str_el4(elcoor, ul) elif iet == 2: epsG, _ = fe.str_el6(elcoor, ul) elif iet == 3: epsG, _ = fe.str_el3(elcoor, ul) for cont, node in enumerate(IELCON[i, :]): E_nodes[node, 0] = E_nodes[node, 0] + epsG[cont, 0] E_nodes[node, 1] = E_nodes[node, 1] + epsG[cont, 1] E_nodes[node, 2] = E_nodes[node, 2] + epsG[cont, 2] S_nodes[node, 0] = S_nodes[node, 0] + fact1*epsG[cont, 0] \ + fact2*epsG[cont, 1] S_nodes[node, 1] = S_nodes[node, 1] + fact2*epsG[cont, 0] \ + fact1*epsG[cont, 1] S_nodes[node, 2] = S_nodes[node, 2] + shear * epsG[cont, 2] el_nodes[node] = el_nodes[node] + 1 E_nodes[:, 0] = E_nodes[:, 0] / el_nodes E_nodes[:, 1] = E_nodes[:, 1] / el_nodes E_nodes[:, 2] = E_nodes[:, 2] / el_nodes S_nodes[:, 0] = S_nodes[:, 0] / el_nodes S_nodes[:, 1] = S_nodes[:, 1] / el_nodes S_nodes[:, 2] = S_nodes[:, 2] / el_nodes return E_nodes, S_nodes
def strain_nodes(IELCON, UU, ne, COORD, elements, mats): """Compute averaged strains and stresses at nodes First, the variable is extrapolated from the Gauss point to nodes for each element. Then, these values are averaged according to the number of element that share that node. The theory for this technique can be found in [1]_. Parameters ---------- IELCON : ndarray (int) Array with the nodes numbers for each element. UU : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. ne : int Number of elements. COORD : ndarray (float). Array with nodes coordinates. elements : ndarray (int) Array with the node number for the nodes that correspond to each element. Returns ------- E_nodes : ndarray Strains evaluated at the nodes. References ---------- .. [1] O.C. Zienkiewicz and J.Z. Zhu, The Superconvergent patch recovery and a posteriori error estimators. Part 1. The recovery technique, Int. J. Numer. Methods Eng., 33, 1331-1364 (1992). """ iet = elements[0, 1] ndof, nnodes, ngpts = fe.eletype(iet) elcoor = np.zeros([nnodes, 2]) E_nodes = np.zeros([COORD.shape[0], 3]) S_nodes = np.zeros([COORD.shape[0], 3]) el_nodes = np.zeros([COORD.shape[0]], dtype=int) ul = np.zeros([ndof]) for i in range(ne): young, poisson = mats[elements[i, 2], :] shear = young / (2 * (1 + poisson)) fact1 = young / (1 - poisson**2) fact2 = poisson * young / (1 - poisson**2) for j in range(nnodes): elcoor[j, 0] = COORD[IELCON[i, j], 0] elcoor[j, 1] = COORD[IELCON[i, j], 1] for j in range(ndof): ul[j] = UU[i, j] if iet == 1: epsG, xl = fe.str_el4(elcoor, ul) extrap0 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 0]) extrap1 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 1]) extrap2 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 2]) elif iet == 2: epsG, xl = fe.str_el6(elcoor, ul) extrap0 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 0]) extrap1 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 1]) extrap2 = interp2d(xl[:, 0], xl[:, 1], epsG[:, 2]) elif iet == 3: epsG, xl = fe.str_el3(elcoor, ul) extrap0 = lambda x, y: epsG[0, 0] extrap1 = lambda x, y: epsG[0, 1] extrap2 = lambda x, y: epsG[0, 2] for node in IELCON[i, :]: x, y = COORD[node, :] E_nodes[node, 0] = E_nodes[node, 0] + extrap0(x, y) E_nodes[node, 1] = E_nodes[node, 1] + extrap1(x, y) E_nodes[node, 2] = E_nodes[node, 2] + extrap2(x, y) S_nodes[node, 0] = S_nodes[node, 0] + fact1*extrap0(x, y) \ + fact2*extrap1(x, y) S_nodes[node, 1] = S_nodes[node, 1] + fact2*extrap0(x, y) \ + fact1*extrap1(x, y) S_nodes[node, 2] = S_nodes[node, 2] + shear * extrap2(x, y) el_nodes[node] = el_nodes[node] + 1 E_nodes[:, 0] = E_nodes[:, 0] / el_nodes E_nodes[:, 1] = E_nodes[:, 1] / el_nodes E_nodes[:, 2] = E_nodes[:, 2] / el_nodes S_nodes[:, 0] = S_nodes[:, 0] / el_nodes S_nodes[:, 1] = S_nodes[:, 1] / el_nodes S_nodes[:, 2] = S_nodes[:, 2] / el_nodes return E_nodes, S_nodes