def __init__(self, element, degree = 1, boundary_function = None): if degree > 1 and boundary_function is None: raise Exception("Sorry. A boundary function is needed in" + " order to describe a higher order polynomial" + " mapping. Either choose degree = 1 or provide" + " a boundary function.") self.element = element self.basis_fncs = basis_from_degree(degree) self.boundary_function = boundary_function # Compute the coefficients of the mapping basis. self.compute_coefficients() # The interface with the fast c++ evaluation code. self.eval = MappingEval(self.basis_fncs, self.coefficients)
class PolynomialMapping(object): """ This class manages the mapping between physical coordinates and reference coordinates. Most of the time, this class will be used as a linear mapping. However, if a curved mesh is desired, a higher degree mapping can be used. Just specify degree > 1 and a boundary function. It is also necessary to properly specify the vertex parameter for each vertex. These will be linearly interpolated when a new point is added. Besides translating reference to physical points, the class also provides jacobians to be used when a change of variables is performed under an integral. Normal vectors are also provided. """ def __init__(self, element, degree = 1, boundary_function = None): if degree > 1 and boundary_function is None: raise Exception("Sorry. A boundary function is needed in" + " order to describe a higher order polynomial" + " mapping. Either choose degree = 1 or provide" + " a boundary function.") self.element = element self.basis_fncs = basis_from_degree(degree) self.boundary_function = boundary_function # Compute the coefficients of the mapping basis. self.compute_coefficients() # The interface with the fast c++ evaluation code. self.eval = MappingEval(self.basis_fncs, self.coefficients) def compute_coefficients(self): # This is basically an interpolation of the boundary function # onto the basis self.coefficients = np.empty((2, self.basis_fncs.n_fncs)) left_vertex = self.element.vertex1 right_vertex = self.element.vertex2 left_param = left_vertex.param right_param = right_vertex.param self.coefficients[:, 0] = left_vertex.loc for i in range(1, self.basis_fncs.n_fncs - 1): x_hat = self.basis_fncs.nodes[i] t = (1 - x_hat) * left_param + x_hat * right_param self.coefficients[:, i] = self.boundary_function(t) self.coefficients[:, -1] = right_vertex.loc def get_physical_point(self, x_hat): """ Use the mapping defined by the coefficients and basis functions to convert coordinates """ return np.array(self.eval.get_physical_point(x_hat)) def get_jacobian(self, x_hat): """ Use the derivative of the mapping defined by the coefficients/basis to get the determinant of the jacobian! This is used to change integration coordinates from physical to reference elements. """ return self.eval.get_jacobian(x_hat) def get_normal(self, x_hat): """ Use the derivative of the mapping to determine the tangent vector and thus to determine the local normal vector. """ return np.array(self.eval.get_normal(x_hat)) def get_linear_approximation(self): """ Computes a small number of linear segments that approximate this element. """ verts = [self.element.vertex1] for i in range(1, self.basis_fncs.n_fncs - 1): x_hat = self.basis_fncs.nodes[i] phys_pt = self.get_physical_point(x_hat) verts.append(Vertex(phys_pt)) verts.append(self.element.vertex2) return verts