def __init__(self, nodes, vertices, elements, connect): '''Instantiate the finite element mesh Parameters ---------- nodes : list of int nodes[i] is the node label of the ith node vertices : ndarray of real vertices[i] are the nodal coordinates of the ith node elements : list of int elements[i] is the element label of the ith element connect : ndarray connect[i, j] is the jth node of the ith element ''' # get nodal coordinates self.nodes = aslist(nodes) self.vertices = np.asarray(vertices) if len(self.vertices.shape) == 1: self.dimension = 1 # hard coded for now else: self.dimension = self.vertices.shape[1] # get element connectivity self.elements = aslist(elements) self.connect = np.asarray(connect) # Repository to hold element blocks, sidesets self.blocks = BlockRepository() self.nodesets = NodesetRepository()
def ElementBlock(self, name=None, elements=None): '''Assign elements to an element block''' if name is None: i = 1 while True: name = 'Block-{0}'.format(i) if name not in self.blocks: break i += 1 if i > MAX_NUM_SETS: raise ValueError('maximum number of blocks exceeded') if name in self.blocks: raise ValueError('{0}: element block already exists'.format(name)) if isstr(elements): if elements.lower() == 'all': elements = [x for x in self.elements] elif elements.lower() == 'unassigned': assigned = [] for elem_blk in self.element_blocks: assigned.extend(elem_blk.elements) elements = list(set(self.elements) - set(assigned)) elements = sorted(elements) else: raise ValueError('{0}: unrecognized option'.format(elements)) else: elements = np.asarray(elements, dtype=np.int) elements = aslist(elements) try: elconn = self.connectivity(elements) except ValueError: raise ValueError('cannot assign elements of different ' 'order to block {0}'.format(name)) self.blocks[name] = ElementBlock(name, elements) return self.blocks[name]
def __init__(self, name, elements): self.name = name self.elements = aslist(elements)
def solve_system(nodes, vertices, elements, connect, k, bcs, cfs, num_dof_per_node=None, bc_method='default'): '''Computes the dependent variable of a linear system Ku = F by finite elements Parameters ---------- nodes : list nodes[i] is the label of node i vertices : array vertices[i] is the nodal coordinates of the node labeled nodes[i] elements : list elements[i] is the label of element i connect : connect[i,j] is the jth node of element i k : list k[i] is the stiffness of the ith element bcs : list List of nodal boundary conditions. bcs[i] = (n, dof, bc) where n is the node number, dof is one of x or y, and bc is the magnitude of the nodal displacement cfs : list List of nodal forces. cfs[i] = (n, dof, f) where n is the node number, dof is one of x or y, and f is the magnitude of the force Returns ------- u : ndarray Nodal displacements r : ndarray Nodal reactions ''' nodes = aslist(nodes) elements = aslist(elements) vertices = np.asarray(vertices) connect = np.asarray(connect) # Check that user input is consistent if len(vertices.shape) == 1: # we want vertices to have at least 1 column vertices = np.reshape(vertices, (vertices.shape[0], 1)) num_node, num_dim = vertices.shape errors = 0 num_elem = connect.shape[0] if num_elem != len(k): logging.error('wrong number of element stiffnesses') errors += 1 if connect.shape[1] != 2: logging.error('expected 2 nodes per element') errors += 1 nun = len(np.unique(connect)) if nun != num_node: s = 'orphaned nodes in vertices' if nun < num_node: logging.error(s) errors += 1 else: logging.warn(s) # make sure forces and boundary conditions not applied to same node bci = [bc[0] for bc in bcs] if any(cf[0] in bci for cf in cfs): logging.error('concentrated force and displacement ' 'imposed on same node[s]') errors += 1 # make sure that the system is stable if len(bcs) <= 0: logging.error('system requires at least one prescribed displacement ' 'to be stable') errors += 1 if errors: raise SystemExit('stopping due to previous errors') # total number of degrees of freedom num_dof_per_node = num_dof_per_node or num_dim num_dof = num_node * num_dof_per_node # Assemble stiffness K = np.zeros((num_dof, num_dof)) nd = num_dof_per_node for (el, econn) in enumerate(connect): i = nodes.index(econn[0]) * num_dof_per_node j = nodes.index(econn[1]) * num_dof_per_node K[i:i+nd, i:i+nd] += k[el] K[j:j+nd, j:j+nd] += k[el] K[i:i+nd, j:j+nd] -= k[el] K[j:j+nd, i:i+nd] -= k[el] # Assemble force F = np.zeros(num_dof) for (node, dof, cf) in cfs: i = nodes.index(node) * num_dof_per_node + DOFS[dof.lower()] F[i] = cf # Apply boundary conditions on copies of K and F that we retain K and F # for later use. Kbc = np.array(K) Fbc = np.array(F) X = 1.e9 * np.amax(k) for (node, dof, bc) in bcs: i = nodes.index(node) * num_dof_per_node + DOFS[dof.lower()] if bc_method == 'default': # Default method - apply bcs such that the global stiffness # remains symmetric # Modify the RHS Fbc -= [Kbc[j, i] * bc for j in range(num_dof)] Fbc[i] = bc # Modify the stiffness Kbc[i, :] = 0 Kbc[:, i] = 0 Kbc[i, i] = 1 elif bc_method == 'penalty': Kbc[i, i] = X Fbc[i] = X * bc else: raise ValueError('unknown bc_method {0}'.format(method)) u = np.linalg.solve(Kbc, Fbc) r = np.dot(K, u) - F return u, r
def solve_system(nodes, vertices, elements, connect, k, bcs, cfs, num_dof_per_node=None, bc_method='default'): '''Computes the dependent variable of a linear system Ku = F by finite elements Parameters ---------- nodes : list nodes[i] is the label of node i vertices : array vertices[i] is the nodal coordinates of the node labeled nodes[i] elements : list elements[i] is the label of element i connect : connect[i,j] is the jth node of element i k : list k[i] is the stiffness of the ith element bcs : list List of nodal boundary conditions. bcs[i] = (n, dof, bc) where n is the node number, dof is one of x or y, and bc is the magnitude of the nodal displacement cfs : list List of nodal forces. cfs[i] = (n, dof, f) where n is the node number, dof is one of x or y, and f is the magnitude of the force Returns ------- u : ndarray Nodal displacements r : ndarray Nodal reactions ''' nodes = aslist(nodes) elements = aslist(elements) vertices = np.asarray(vertices) connect = np.asarray(connect) # Check that user input is consistent if len(vertices.shape) == 1: # we want vertices to have at least 1 column vertices = np.reshape(vertices, (vertices.shape[0], 1)) num_node, num_dim = vertices.shape errors = 0 num_elem = connect.shape[0] if num_elem != len(k): logging.error('wrong number of element stiffnesses') errors += 1 if connect.shape[1] != 2: logging.error('expected 2 nodes per element') errors += 1 nun = len(np.unique(connect)) if nun != num_node: s = 'orphaned nodes in vertices' if nun < num_node: logging.error(s) errors += 1 else: logging.warn(s) # make sure forces and boundary conditions not applied to same node bci = [bc[0] for bc in bcs] if any(cf[0] in bci for cf in cfs): logging.error('concentrated force and displacement ' 'imposed on same node[s]') errors += 1 # make sure that the system is stable if len(bcs) <= 0: logging.error('system requires at least one prescribed displacement ' 'to be stable') errors += 1 if errors: raise SystemExit('stopping due to previous errors') # total number of degrees of freedom num_dof_per_node = num_dof_per_node or num_dim num_dof = num_node * num_dof_per_node # Assemble stiffness K = np.zeros((num_dof, num_dof)) nd = num_dof_per_node for (el, econn) in enumerate(connect): i = nodes.index(econn[0]) * num_dof_per_node j = nodes.index(econn[1]) * num_dof_per_node K[i:i + nd, i:i + nd] += k[el] K[j:j + nd, j:j + nd] += k[el] K[i:i + nd, j:j + nd] -= k[el] K[j:j + nd, i:i + nd] -= k[el] # Assemble force F = np.zeros(num_dof) for (node, dof, cf) in cfs: i = nodes.index(node) * num_dof_per_node + DOFS[dof.lower()] F[i] = cf # Apply boundary conditions on copies of K and F that we retain K and F # for later use. Kbc = np.array(K) Fbc = np.array(F) X = 1.e9 * np.amax(k) for (node, dof, bc) in bcs: i = nodes.index(node) * num_dof_per_node + DOFS[dof.lower()] if bc_method == 'default': # Default method - apply bcs such that the global stiffness # remains symmetric # Modify the RHS Fbc -= [Kbc[j, i] * bc for j in range(num_dof)] Fbc[i] = bc # Modify the stiffness Kbc[i, :] = 0 Kbc[:, i] = 0 Kbc[i, i] = 1 elif bc_method == 'penalty': Kbc[i, i] = X Fbc[i] = X * bc else: raise ValueError('unknown bc_method {0}'.format(method)) u = np.linalg.solve(Kbc, Fbc) r = np.dot(K, u) - F return u, r