def face_normals(g): """ Check if the face normals are actually normal to the faces. Args: g (grid): Grid, or a subclass, with geometry fields computed. """ nodes, faces, _ = sps.find(g.face_nodes) for f in np.arange(g.num_faces): loc = slice(g.face_nodes.indptr[f], g.face_nodes.indptr[f + 1]) normal = g.face_normals[:, f] tangent = cg.compute_tangent(g.nodes[:, nodes[loc]]) assert np.isclose(np.dot(normal, tangent), 0)
def create_embedded_line_grid(loc_coord, glob_id, tol=1e-4): loc_center = np.mean(loc_coord, axis=1).reshape((-1, 1)) loc_coord -= loc_center # Check that the points indeed form a line if not cg.is_collinear(loc_coord, tol): raise ValueError("Elements are not colinear") # Find the tangent of the line tangent = cg.compute_tangent(loc_coord) # Projection matrix rot = cg.project_line_matrix(loc_coord, tangent) loc_coord_1d = rot.dot(loc_coord) # The points are now 1d along one of the coordinate axis, but we # don't know which yet. Find this. sum_coord = np.sum(np.abs(loc_coord_1d), axis=1) sum_coord /= np.amax(sum_coord) active_dimension = np.logical_not( np.isclose(sum_coord, 0, atol=tol, rtol=0)) # Check that we are indeed in 1d assert np.sum(active_dimension) == 1 # Sort nodes, and create grid coord_1d = loc_coord_1d[active_dimension] sort_ind = np.argsort(coord_1d)[0] sorted_coord = coord_1d[0, sort_ind] g = structured.TensorGrid(sorted_coord) # Project back to active dimension nodes = np.zeros(g.nodes.shape) nodes[active_dimension] = g.nodes[0] g.nodes = nodes # Project back again to 3d coordinates irot = rot.transpose() g.nodes = irot.dot(g.nodes) g.nodes += loc_center # Add mapping to global point numbers g.global_point_ind = glob_id[sort_ind] return g
def __compute_geometry_1d(self): "Compute 1D geometry" self.face_areas = np.ones(self.num_faces) fn = self.face_nodes.indices n = fn.size self.face_centers = self.nodes[:, fn] self.face_normals = np.tile(cg.compute_tangent(self.nodes), (n, 1)).T cf = self.cell_faces.indices xf1 = self.face_centers[:, cf[::2]] xf2 = self.face_centers[:, cf[1::2]] self.cell_volumes = np.linalg.norm(xf1 - xf2, axis=0) self.cell_centers = 0.5 * (xf1 + xf2) # Ensure that normal vector direction corresponds with sign convention # in self.cellFaces def nrm(u): return np.sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]) [fi, ci, val] = sps.find(self.cell_faces) _, idx = np.unique(fi, return_index=True) sgn = val[idx] fc = self.face_centers[:, fi[idx]] cc = self.cell_centers[:, ci[idx]] v = fc - cc # Prolong the vector from cell to face center in the direction of the # normal vector. If the prolonged vector is shorter, the normal should # flipped vn = v + nrm(v) * self.face_normals[:, fi[idx]] * 0.001 flip = np.logical_or( np.logical_and(nrm(v) > nrm(vn), sgn > 0), np.logical_and(nrm(v) < nrm(vn), sgn < 0), ) self.face_normals[:, flip] *= -1