def _assemble(self, mu=None): g = self.grid bi = self.boundary_info # evaluate function at all quadrature points -> shape = (g.size(0), number of quadrature points) F = self.function(g.quadrature_points(0, order=self.order), mu=mu) # evaluate the shape functions at the quadrature points on the reference # element -> shape = (number of shape functions, number of quadrature points) q, w = g.reference_element.quadrature(order=self.order) if g.dim == 2: SF = np.array(((1 - q[..., 0]) * (1 - q[..., 1]), (1 - q[..., 1]) * (q[..., 0]), (q[..., 0]) * (q[..., 1]), (q[..., 1]) * (1 - q[..., 0]))) else: raise NotImplementedError # integrate the products of the function with the shape functions on each element # -> shape = (g.size(0), number of shape functions) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(0), w).ravel() # map local DOFs to global DOFs # FIXME This implementation is horrible, find a better way! SF_I = g.subentities(0, g.dim).ravel() I = np.array(coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))).todense()).ravel() # neumann boundary treatment if bi is not None and bi.has_neumann and self.neumann_data is not None: NI = bi.neumann_boundaries(1) F = -self.neumann_data(g.quadrature_points(1, order=self.order)[NI], mu=mu) q, w = line.quadrature(order=self.order) SF = np.squeeze(np.array([1 - q, q])) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(1)[NI], w).ravel() SF_I = g.subentities(1, 2)[NI].ravel() I += np.array(coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))) .todense()).ravel() if bi is not None and bi.has_robin and self.robin_data is not None: RI = bi.robin_boundaries(1) xref = g.quadrature_points(1, order=self.order)[RI] F = self.robin_data[0](xref, mu=mu) * self.robin_data[1](xref, mu=mu) q, w = line.quadrature(order=self.order) SF = np.squeeze(np.array([1 - q, q])) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(1)[RI], w).ravel() SF_I = g.subentities(1, 2)[RI].ravel() I += np.array(coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))) .todense()).ravel() if bi is not None and bi.has_dirichlet: DI = bi.dirichlet_boundaries(g.dim) if self.dirichlet_data is not None: I[DI] = self.dirichlet_data(g.centers(g.dim)[DI], mu=mu) else: I[DI] = 0 return I.reshape((1, -1))
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info if g.dim > 2: raise NotImplementedError if bi is None or not bi.has_robin or self.robin_data is None: return coo_matrix((g.size(g.dim), g.size(g.dim))).tocsc() RI = bi.robin_boundaries(1) if g.dim == 1: robin_c = self.robin_data[0](g.centers(1)[RI], mu=mu) I = coo_matrix((robin_c, (RI, RI)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy() else: xref = g.quadrature_points(1, order=self.order)[RI] # xref(robin-index, quadraturepoint-index) if self.robin_data[0].shape_range == (): robin_c = self.robin_data[0](xref, mu=mu) else: robin_elements = g.superentities(1, 0)[RI, 0] robin_indices = g.superentity_indices(1, 0)[RI, 0] normals = g.unit_outer_normals()[robin_elements, robin_indices] robin_values = self.robin_data[0](xref, mu=mu) robin_c = np.einsum('ei,eqi->eq', normals, robin_values) # robin_c(robin-index, quadraturepoint-index) q, w = line.quadrature(order=self.order) SF = np.squeeze(np.array([1 - q, q])) SF_INTS = np.einsum('ep,pi,pj,e,p->eij', robin_c, SF, SF, g.integration_elements(1)[RI], w).ravel() SF_I0 = np.repeat(g.subentities(1, g.dim)[RI], 2).ravel() SF_I1 = np.tile(g.subentities(1, g.dim)[RI], [1, 2]).ravel() I = coo_matrix((SF_INTS, (SF_I0, SF_I1)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy()
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info NI = bi.boundaries(self.boundary_type, 1) if self.boundary_type else g.boundaries(1) if g.dim == 1: I = np.zeros(self.range.dim) I[NI] = self.function(g.centers(1)[NI]) else: F = self.function(g.quadrature_points(1, order=self.order)[NI], mu=mu) q, w = line.quadrature(order=self.order) # remove last dimension of q, as line coordinates are one dimensional q = q[:, 0] SF = np.array([1 - q, q]) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(1)[NI], w).ravel() SF_I = g.subentities(1, 2)[NI].ravel() I = coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))).toarray().ravel() if self.dirichlet_clear_dofs and bi.has_dirichlet: DI = bi.dirichlet_boundaries(g.dim) I[DI] = 0 return I.reshape((-1, 1))
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info if g.dim > 2: raise NotImplementedError if bi is None or not bi.has_robin or self.robin_data is None: return coo_matrix((g.size(g.dim), g.size(g.dim))).tocsc() RI = bi.robin_boundaries(1) if g.dim == 1: robin_c = self.robin_data[0](g.centers(1)[RI], mu=mu) I = coo_matrix((robin_c, (RI, RI)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy() else: xref = g.quadrature_points(1, order=self.order)[RI] robin_c = self.robin_data[0](xref, mu=mu) q, w = line.quadrature(order=self.order) SF = np.squeeze(np.array([1 - q, q])) SF_INTS = np.einsum('ep,pi,pj,e,p->eij', robin_c, SF, SF, g.integration_elements(1)[RI], w).ravel() SF_I0 = np.repeat(g.subentities(1, g.dim)[RI], 2).ravel() SF_I1 = np.tile(g.subentities(1, g.dim)[RI], [1, 2]).ravel() I = coo_matrix((SF_INTS, (SF_I0, SF_I1)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy()
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info # our shape functions if g.dim == 2: SF = [ lambda X: 1 - X[..., 0] - X[..., 1], lambda X: X[..., 0], lambda X: X[..., 1] ] q, w = triangle.quadrature(order=2) elif g.dim == 1: SF = [lambda X: 1 - X[..., 0], lambda X: X[..., 0]] q, w = line.quadrature(order=2) else: raise NotImplementedError # evaluate the shape functions on the quadrature points SFQ = np.array(tuple(f(q) for f in SF)) self.logger.info( 'Integrate the products of the shape functions on each element') # -> shape = (g.size(0), number of shape functions ** 2) if self.coefficient_function is not None: C = self.coefficient_function(self.grid.centers(0), mu=mu) SF_INTS = np.einsum('iq,jq,q,e,e->eij', SFQ, SFQ, w, g.integration_elements(0), C).ravel() del C else: SF_INTS = np.einsum('iq,jq,q,e->eij', SFQ, SFQ, w, g.integration_elements(0)).ravel() del SFQ self.logger.info('Determine global dofs ...') SF_I0 = np.repeat(g.subentities(0, g.dim), g.dim + 1, axis=1).ravel() SF_I1 = np.tile(g.subentities(0, g.dim), [1, g.dim + 1]).ravel() self.logger.info('Boundary treatment ...') if bi.has_dirichlet: if self.dirichlet_clear_rows: SF_INTS = np.where(bi.dirichlet_mask(g.dim)[SF_I0], 0, SF_INTS) if self.dirichlet_clear_columns: SF_INTS = np.where(bi.dirichlet_mask(g.dim)[SF_I1], 0, SF_INTS) if not self.dirichlet_clear_diag and ( self.dirichlet_clear_rows or self.dirichlet_clear_columns): SF_INTS = np.hstack( (SF_INTS, np.ones(bi.dirichlet_boundaries(g.dim).size))) SF_I0 = np.hstack((SF_I0, bi.dirichlet_boundaries(g.dim))) SF_I1 = np.hstack((SF_I1, bi.dirichlet_boundaries(g.dim))) self.logger.info('Assemble system matrix ...') A = coo_matrix((SF_INTS, (SF_I0, SF_I1)), shape=(g.size(g.dim), g.size(g.dim))) del SF_INTS, SF_I0, SF_I1 A = csc_matrix( A).copy() # See DiffusionOperatorP1 for why copy() is necessary return A
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info # our shape functions if g.dim == 2: SF = [lambda X: 1 - X[..., 0] - X[..., 1], lambda X: X[..., 0], lambda X: X[..., 1]] q, w = triangle.quadrature(order=2) elif g.dim == 1: SF = [lambda X: 1 - X[..., 0], lambda X: X[..., 0]] q, w = line.quadrature(order=2) else: raise NotImplementedError # evaluate the shape functions on the quadrature points SFQ = np.array(tuple(f(q) for f in SF)) self.logger.info('Integrate the products of the shape functions on each element') # -> shape = (g.size(0), number of shape functions ** 2) if self.coefficient_function is not None: C = self.coefficient_function(self.grid.centers(0), mu=mu) SF_INTS = np.einsum('iq,jq,q,e,e->eij', SFQ, SFQ, w, g.integration_elements(0), C).ravel() del C else: SF_INTS = np.einsum('iq,jq,q,e->eij', SFQ, SFQ, w, g.integration_elements(0)).ravel() del SFQ self.logger.info('Determine global dofs ...') SF_I0 = np.repeat(g.subentities(0, g.dim), g.dim + 1, axis=1).ravel() SF_I1 = np.tile(g.subentities(0, g.dim), [1, g.dim + 1]).ravel() self.logger.info('Boundary treatment ...') if bi.has_dirichlet: if self.dirichlet_clear_rows: SF_INTS = np.where(bi.dirichlet_mask(g.dim)[SF_I0], 0, SF_INTS) if self.dirichlet_clear_columns: SF_INTS = np.where(bi.dirichlet_mask(g.dim)[SF_I1], 0, SF_INTS) if not self.dirichlet_clear_diag and (self.dirichlet_clear_rows or self.dirichlet_clear_columns): SF_INTS = np.hstack((SF_INTS, np.ones(bi.dirichlet_boundaries(g.dim).size))) SF_I0 = np.hstack((SF_I0, bi.dirichlet_boundaries(g.dim))) SF_I1 = np.hstack((SF_I1, bi.dirichlet_boundaries(g.dim))) self.logger.info('Assemble system matrix ...') A = coo_matrix((SF_INTS, (SF_I0, SF_I1)), shape=(g.size(g.dim), g.size(g.dim))) del SF_INTS, SF_I0, SF_I1 A = csc_matrix(A).copy() # See DiffusionOperatorP1 for why copy() is necessary return A
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info # evaluate function at all quadrature points -> shape = (g.size(0), number of quadrature points) F = self.function(g.quadrature_points(0, order=self.order), mu=mu) # evaluate the shape functions at the quadrature points on the reference # element -> shape = (number of shape functions, number of quadrature points) q, w = g.reference_element.quadrature(order=self.order) if g.dim == 1: SF = np.array((1 - q[..., 0], q[..., 0])) elif g.dim == 2: SF = np.array(((1 - np.sum(q, axis=-1)), q[..., 0], q[..., 1])) else: raise NotImplementedError # integrate the products of the function with the shape functions on each element # -> shape = (g.size(0), number of shape functions) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(0), w).ravel() # map local DOFs to global DOFs # FIXME This implementation is horrible, find a better way! SF_I = g.subentities(0, g.dim).ravel() I = np.array(coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))).todense()).ravel() # boundary treatment if bi is not None and bi.has_neumann and self.neumann_data is not None: NI = bi.neumann_boundaries(1) if g.dim == 1: I[NI] -= self.neumann_data(g.centers(1)[NI]) else: F = -self.neumann_data(g.quadrature_points(1, order=self.order)[NI], mu=mu) q, w = line.quadrature(order=self.order) SF = np.squeeze(np.array([1 - q, q])) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(1)[NI], w).ravel() SF_I = g.subentities(1, 2)[NI].ravel() I += np.array(coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))) .todense()).ravel() if bi is not None and bi.has_dirichlet: DI = bi.dirichlet_boundaries(g.dim) if self.dirichlet_data is not None: I[DI] = self.dirichlet_data(g.centers(g.dim)[DI], mu=mu) else: I[DI] = 0 return I.reshape((1, -1))
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info NI = bi.neumann_boundaries(1) F = self.function(g.quadrature_points(1, order=self.order)[NI], mu=mu) q, w = line.quadrature(order=self.order) # remove last dimension of q, as line coordinates are one dimensional q = q[:, 0] SF = np.array([1 - q, q]) SF_INTS = np.einsum('ei,pi,e,i->ep', F, SF, g.integration_elements(1)[NI], w).ravel() SF_I = g.subentities(1, 2)[NI].ravel() I = coo_matrix((SF_INTS, (np.zeros_like(SF_I), SF_I)), shape=(1, g.size(g.dim))).toarray().ravel() if self.dirichlet_clear_dofs and bi.has_dirichlet: DI = bi.dirichlet_boundaries(g.dim) I[DI] = 0 return I.reshape((-1, 1))
def _assemble(self, mu=None): g = self.grid bi = self.boundary_info if g.dim > 2: raise NotImplementedError if bi is None or not bi.has_robin or self.robin_data is None: return coo_matrix((g.size(g.dim), g.size(g.dim))).tocsc() RI = bi.robin_boundaries(1) if g.dim == 1: robin_c = self.robin_data[0](g.centers(1)[RI], mu=mu) I = coo_matrix((robin_c, (RI, RI)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy() else: xref = g.quadrature_points(1, order=self.order)[RI] # xref(robin-index, quadraturepoint-index) if self.robin_data[0].shape_range == (): robin_c = self.robin_data[0](xref, mu=mu) else: robin_elements = g.superentities(1, 0)[RI, 0] robin_indices = g.superentity_indices(1, 0)[RI, 0] normals = g.unit_outer_normals()[robin_elements, robin_indices] robin_values = self.robin_data[0](xref, mu=mu) robin_c = np.einsum('ei,eqi->eq', normals, robin_values) # robin_c(robin-index, quadraturepoint-index) q, w = line.quadrature(order=self.order) # remove last dimension of q, as line coordinates are one dimensional q = q[:, 0] SF = np.array([1 - q, q]) SF_INTS = np.einsum('ep,pi,pj,e,p->eij', robin_c, SF, SF, g.integration_elements(1)[RI], w).ravel() SF_I0 = np.repeat(g.subentities(1, g.dim)[RI], 2).ravel() SF_I1 = np.tile(g.subentities(1, g.dim)[RI], [1, 2]).ravel() I = coo_matrix((SF_INTS, (SF_I0, SF_I1)), shape=(g.size(g.dim), g.size(g.dim))) return csc_matrix(I).copy()