def scatter(DME, UG, ne, neq, elements): """Scatter the nodal displacements vector `UG` over each element Parameters ---------- DME : ndarray (int) Array that shows the connectivity of degrees of freedom. UG : ndarray (float) Array with the computed displacements. ne : int Number of elements. neq : int Number of equations (degrees of freedom). elements : ndarray (int) Array with the node number for the nodes that correspond to each element. Returns ------- UU : ndarray (float) Array with the displacements. This one contains both, the computed and imposed values. """ iet = elements[0, 1] ndof, nnodes, ngpts = fe.eletype(iet) UU = np.zeros([ne, ndof], dtype=np.float) for i in range(ne): for ii in range(ndof): kk = DME[i, ii] if kk != -1: UU[i, ii] = UG[kk] return UU
def eleDisp(Up, iet, dme, i): """ This function find displacements of element i. Returns 1D array with x, y and rotation displacements values in each node. Parameters ---------- Up : Displacement al time t + dtaT (not converged). iet : Element i type dme : Assembly operator that indicates degrees of freedom correspondence of the element. i : Element indicator """ ndof, nnodes, ngpts = fem.eletype(iet) ele_disp = np.zeros((ndof,)) # for j in range (ndof): ID_dof = dme[j] if ID_dof == -1: ele_disp[j] = 0.0 else: ele_disp[j] = Up[ID_dof] # End if #End for return ele_disp
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 retriever(elements , mats , nodes , i, uel=None): """Computes the elemental stiffness matrix of element i Parameters ---------- elements : ndarray Array with the number for the nodes in each element. mats : ndarray. Array with the material profiles. nodes : ndarray. Array with the nodal numbers and coordinates. i : int. Identifier of the element to be assembled. Returns ------- kloc : ndarray (float) Array with the local stiffness matrix. ndof : int. Number of degrees of fredom of the current element. """ IELCON = np.zeros([9], dtype=np.integer) iet = elements[i, 1] ndof, nnodes, ngpts = fem.eletype(iet) elcoor = np.zeros([nnodes, 2]) im = np.int(elements[i, 2]) par0, par1 = mats[im, :] for j in range(nnodes): IELCON[j] = elements[i, j+3] elcoor[j, 0] = nodes[IELCON[j], 1] elcoor[j, 1] = nodes[IELCON[j], 2] if uel is None: if iet == 1: kloc = ue.uel4nquad(elcoor, par1, par0) elif iet == 2: kloc = ue.uel6ntrian(elcoor, par1, par0) elif iet == 3: kloc = ue.uel3ntrian(elcoor, par1, par0) elif iet == 5: kloc = ue.uelspring(elcoor, par1, par0) elif iet == 6: kloc = ue.ueltruss2D(elcoor, par1, par0) elif iet == 7: kloc = ue.uelbeam2DU(elcoor, par1, par0) else: kloc, ndof, iet = uel(elcoor, par1, par0) return kloc, ndof, iet
def DME(nodes, elements): """Counts active equations, creates BCs array IBC[] and the assembly operator DME[] Parameters ---------- nodes : ndarray. Array with the nodal numbers and coordinates. elements : ndarray Array with the number for the nodes in each element. Returns ------- DME : ndarray (int) Assembly operator. IBC : ndarray (int) Boundary conditions array. neq : int Number of active equations in the system. """ nels = elements.shape[0] IELCON = np.zeros([nels, 9], dtype=np.integer) DME = np.zeros([nels, 18], dtype=np.integer) neq, IBC = eqcounter(nodes) for i in range(nels): iet = elements[i, 1] ndof, nnodes, ngpts = fem.eletype(iet) for j in range(nnodes): IELCON[i, j] = elements[i, j+3] kk = IELCON[i, j] for l in range(2): DME[i, 2*j+l] = IBC[kk, l] return DME , IBC , neq
def DME(IBC, ne, elements): """Create the assembly operator Create the assembly operator DME and processes the element connectivity array IELCON Parameters ---------- IBC : ndarray Array that maps the nodes with number of equations. ne : int Number of elements. elements : ndarray Array with the number for the nodes in each element. Returns ------- DME : ndarray (int) Assembly operator. IELCON : ndarray (int) Element connectivity. """ IELCON = np.zeros([ne, 9], dtype=np.integer) DME = np.zeros([ne, 18], dtype=np.integer) for i in range(ne): iet = elements[i, 1] ndof, nnodes, ngpts = fem.eletype(iet) for j in range(nnodes): IELCON[i, j] = elements[i, j + 3] kk = IELCON[i, j] for l in range(2): DME[i, 2 * j + l] = IBC[kk, l] return DME, IELCON
def DME(IBC, ne, elements): """Create the assembly operator Create the assembly operator DME and processes the element connectivity array IELCON Parameters ---------- IBC : ndarray Array that maps the nodes with number of equations. ne : int Number of elements. elements : ndarray Array with the number for the nodes in each element. Returns ------- DME : ndarray (int) Assembly operator. IELCON : ndarray (int) Element connectivity. """ IELCON = np.zeros([ne, 9], dtype=np.integer) DME = np.zeros([ne, 18], dtype=np.integer) for i in range(ne): iet = elements[i, 1] ndof, nnodes, ngpts = fem.eletype(iet) for j in range(nnodes): IELCON[i, j] = elements[i, j+3] kk = IELCON[i, j] for l in range(2): DME[i, 2*j+l] = IBC[kk, l] return DME, IELCON
def readin(folder): """Read the input files""" inipar = np.loadtxt(folder + '01_Inipar.txt', ndmin=2, usecols=(0), skiprows=6) nodes = np.loadtxt(folder + '03_Nodes.txt' , ndmin=2, skiprows=3) loads = np.loadtxt(folder + '05_Nodal_loads.txt' , ndmin=2, skiprows=3) # # ------------------------------------------------------------------------------------- # Read constraints file and identify if there is any diaphfragm or constraint const = np.loadtxt(folder + '07_DOF_Constraints.txt' , ndmin=2, skiprows=9) DPH_flag = 0 CST_flag = 0 # if len(const) != 0: if max(const[:,1]) >= 0: DPH_flag = 1 if min(const[:,1]) < 0: CST_flag = 1 # End if #End if const = list(const) const.insert(0,CST_flag) const.insert(0,DPH_flag) # # ------------------------------------------------------------------------------------- # NLSTA = int(inipar[5,0]) NLDYNA = int(inipar[6,0]) # if (NLSTA == 1) and (NLDYNA == 0): Seismo_signal = [] elif (NLSTA == 0) and (NLDYNA == 1): Seismo_signal = np.loadtxt(folder + '06_Seismo_signal.txt' , skiprows=5) elif (NLSTA == 1) and (NLDYNA == 1): Seismo_signal = np.loadtxt(folder + '06_Seismo_signal.txt' , skiprows=5) # End if # # ------------------------------------------------------------------------------------- # Read material - parameters file mat_file = open(folder + '02_Mater.txt', 'r') # mats = [] matflag = 0 for line in mat_file: if matflag == 1: l = np.array(line.split(), dtype = float) mats.append(l) # End if if line == 'PARAMETERS INFORMATION\n': matflag = 1 #End if #End for # # ------------------------------------------------------------------------------------- # Read elements file eles_file = open(folder + '04_Eles.txt', 'r') # elements = [] eleflag = 0 for line in eles_file: if eleflag == 1: l = np.array(line.split(), dtype = int) elements.append(l) #End if if line == 'ELEMENTS\n': eleflag = 1 #End if #End for # # ------------------------------------------------------------------------------------- # Initialize Msvar (List where state variables of each element will be stocked) Msvar = [] ILF = [] nele = len(elements) # for i in range (nele): # iet = elements[i][1] ndof, nnodes, ngpts = fem.eletype(iet) # if iet == 0: # Linear - 1D Spring nsvar = 1 if iet == 1: # Linear - Simple frame nsvar = 1 if iet == 2: # Linear - Full frame nsvar = 1 if iet == 3: # Linear - 2D Truss nsvar = 1 if iet == 4: # NonLin - 4 noded plate (Rutinas de Jefe) nsvar = 88 if iet == 5: # NonLin - 1D Spring nsvar = 5 if iet == 6: # Lin - 2D shear-rotational Spring nsvar = 1 if iet == 7: # Lin - 1D rotational Spring nsvar = 1 if iet == 8: # NonLin - 1D rotational Spring nsvar = 5 if iet == 9: # NonLin - 1D pile spring for stiff soils nsvar = 4 if iet == 10: # Linear - 3D full frame bending ans shear effects nsvar = 1 # End if # ele_svar = np.zeros((nsvar)) ele_ilf = np.zeros((ndof)) Msvar.append(ele_svar) ILF.append(ele_ilf) # End for # ------------------------------------------------------------------------------------- return inipar, nodes, mats, elements, loads, Msvar, ILF, Seismo_signal, const
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 matassem(IBC, mats, elements, nn, ne, neq, COORD, DME, IELCON): """Assembles the global stiffness matrix KG Parameters ---------- IBC : ndarray (int) Array that maps the nodes with number of equations. mats : ndarray Material properties. elements : ndarray Array with the number for the nodes in each element. nn : int Number of nodes. ne : int Number of elements. neq : int Number of equations in the system after removing the nodes with imposed displacements. COORD : ndarray Coordinates of the nodes. DME : ndarray (int) Assembly operator. IELCON : ndarray (int) Element connectivity. Returns ------- KG : ndarray Global stiffness matrix. """ KG = np.zeros([neq, neq]) for i in range(ne): iet = elements[i, 1] ndof, nnodes, ngpts = fem.eletype(iet) elcoor = np.zeros([nnodes, 2]) kloc = np.zeros([ndof, ndof]) im = elements[i, 2] emod = mats[im, 0] enu = mats[im, 1] dme = np.zeros([ndof], dtype=np.integer) for j in range(nnodes): elcoor[j, 0] = COORD[IELCON[i, j], 0] elcoor[j, 1] = COORD[IELCON[i, j], 1] if iet == 1: kloc = ue.uel4nquad(elcoor, enu, emod) elif iet == 2: kloc = ue.uel6ntrian(elcoor, enu, emod) elif iet == 3: kloc = ue.uel3ntrian(elcoor, enu, emod) for ii in range(ndof): dme[ii] = DME[i, ii] for ii in range(ndof): kk = dme[ii] if kk != -1: for jj in range(ndof): ll = dme[jj] if ll != -1: KG[kk, ll] = KG[kk, ll] + kloc[ii, jj] return KG
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 retriever(Up, svar, dme, ac, elements , mats , nodes , i, uel=None): """Computes the elemental stiffness matrix of element i Parameters ---------- Up : ndarray Array with the nodal displacement at time t svar : python list List with the state variables of the element of the last converged increment. dme : ndarray (int) Assembly operator that indicates degrees of freedom correspondence of the element. ac : 1D array Integration constants elements : ndarray Array with the number for the nodes in each element. mats : ndarray. Array with the material profiles. nodes : ndarray. Array with the nodal numbers and coordinates. i : int. Identifier of the element to be assembled. Returns ------- kloc : ndarray (float) Array with the local stiffness matrix. mloc : ndarray (float) Array with the local mass matrix. cloc : ndarray (float) Array with the local damping matrix. svar : Python list List with the state variables of the current element. ndof : int. Number of degrees of freedom of the current element. """ # iet = elements[i][1] # ndof, nnodes, ngpts = fem.eletype(iet) iele_disp = eleDisp(Up, iet, dme, i) # elcoor = np.zeros([nnodes, 3]) im = np.int(elements[i][2]) par = mats[im] for j in range(nnodes): IELCON = elements[i][j+3] # Index of each node of the element elcoor[j, 0] = nodes[IELCON, 1] # X coordinate of the node elcoor[j, 1] = nodes[IELCON, 2] # X coordinate of the node elcoor[j, 2] = nodes[IELCON, 3] # X coordinate of the node # End for j # if uel is None: if iet == 0: kloc , mloc , cloc , svar, ilf = ue.L_1Dspring(iele_disp, elcoor, par, svar) if iet == 1: kloc , mloc , cloc , svar, ilf = ue.L_sframe(iele_disp, elcoor, par, svar) elif iet == 2: kloc , mloc , cloc , svar, ilf = ue.L_fframe(iele_disp, elcoor, par, svar) elif iet == 3: kloc , mloc , cloc , svar, ilf = ue.L_2Dtruss(iele_disp, elcoor, par, svar) elif iet == 4: kloc , mloc , cloc , svar, ilf = slds.uel4nquad_PLK(elcoor, par, svar, iele_disp) elif iet == 5: kloc , mloc , cloc , svar, ilf = ue.NL_1Dspring(iele_disp, elcoor, par, svar) elif iet == 6: kloc , mloc , cloc , svar, ilf = ue.L_2DRotspg(iele_disp, elcoor, par, svar) elif iet == 7: kloc , mloc , cloc , svar, ilf = ue.L_1DRotspg(iele_disp, elcoor, par, svar) elif iet == 8: kloc , mloc , cloc , svar, ilf = ue.NL_1DRotspg(iele_disp, elcoor, par, svar) elif iet == 9: kloc , mloc , cloc , svar, ilf = ue.NL_1DPileRCK(iele_disp, elcoor, par, svar) elif iet == 10: kloc , mloc , cloc , svar, ilf = ue.L_3Dfframe(iele_disp, elcoor, par, svar) else: kloc, ndof, iet = uel(elcoor, par) return kloc, mloc, cloc, svar, ndof, ilf
def DME(nodes, elements): """Counts active equations, creates BCs array IBC[] and the assembly operator DME[] Parameters ---------- nodes : ndarray. Array with the nodal numbers and coordinates. elements : ndarray Array with the number for the nodes in each element. iet : int (This is not an input for this function) Type of element. These are: 0. Linear - 1D Spring in X direction. 1. Linear - Simple frame. 2. Linear - Full frame. 3. Linear - 2D Truss. 4. NonLin - 4 noded plate. 5. NonLin - 1D Spring in X direction. 6. Linear - 2D Shear-Rotational spring. 7. Linear - 1D Rotational spring. 8. NonLin - 1D Rotational spring. 9. NonLin - 1D pile spring P-Y curve for stiff soil 10. Linear - 3D full frame bending and shear effects Returns ------- DME : ndarray (int) Assembly operator. IBC : ndarray (int) Boundary conditions array. neq : int Number of active equations in the system. """ nels = len(elements) IELCON = np.zeros([nels, 4], dtype=np.integer) # 4 por que es el máximo numero de nodos que conforman un elemento DME = [] neq, IBC = eqcounter(nodes) for i in range(nels): dme = [] iet = elements[i][1] ndof, nnodes, ngpts = fem.eletype(iet) for j in range(nnodes): IELCON[i, j] = elements[i][j+3] kk = IELCON[i, j] # if iet == 0: dme.append(IBC[kk, 0]) elif iet == 1: dme.append(IBC[kk, 0]) dme.append(IBC[kk, 1]) dme.append(IBC[kk, 5]) elif iet == 2: dme.append(IBC[kk, 0]) dme.append(IBC[kk, 1]) dme.append(IBC[kk, 5]) elif iet == 3: dme.append(IBC[kk, 0]) dme.append(IBC[kk, 1]) elif iet == 4: dme.append(IBC[kk, 0]) dme.append(IBC[kk, 1]) elif iet == 5: dme.append(IBC[kk, 0]) elif iet == 6: dme.append(IBC[kk, 1]) dme.append(IBC[kk, 5]) elif iet == 7: dme.append(IBC[kk, 5]) elif iet == 8: dme.append(IBC[kk, 5]) elif iet == 9: dme.append(IBC[kk, 0]) elif iet == 10: dme.append(IBC[kk, 0]) dme.append(IBC[kk, 1]) dme.append(IBC[kk, 2]) dme.append(IBC[kk, 3]) dme.append(IBC[kk, 4]) dme.append(IBC[kk, 5]) #End if # End for j DME.append(dme) # ENd for i return DME, IBC, neq
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