def setup_mesh(self, m): self.m = m self.fault_start_idx = m.get_start('fault') fault_tris = self.m.get_tris('fault') self.unscaled_tri_normals = unscaled_normals(self.m.pts[fault_tris]) self.tri_size = np.linalg.norm(self.unscaled_tri_normals, axis = 1) self.tri_normals = self.unscaled_tri_normals / self.tri_size[:, np.newaxis] self.n_tris = self.m.tris.shape[0] self.basis_dim = 3 self.n_dofs = self.basis_dim * self.n_tris
def setup_mesh(self, m): if type(m) is CombinedMesh: self.m = m else: self.m = CombinedMesh.from_named_pieces([('fault', m)]) self.unscaled_tri_normals = unscaled_normals(self.m.pts[self.m.tris]) self.tri_size = np.linalg.norm(self.unscaled_tri_normals, axis = 1) self.tri_normals = self.unscaled_tri_normals / self.tri_size[:, np.newaxis] self.n_tris = self.m.tris.shape[0] self.basis_dim = 3 self.n_dofs = self.basis_dim * self.n_tris
def __init__(self, nq, pts, tris, tensor_dim = 3): qx, qw = gauss2d_tri(nq) tri_pts = pts[tris] basis = geometry.linear_basis_tri_arr(qx) unscaled_normals = geometry.unscaled_normals(tri_pts) jacobians = geometry.jacobians(unscaled_normals) basis_factors = [] for b1 in range(3): for b2 in range(3): basis_factors.append(np.sum(qw * (basis[:,b1]*basis[:,b2]))) basis_factors = np.array(basis_factors) rows, cols, vals = _mass_op.build_op(basis_factors, jacobians, tensor_dim) n_rows = tris.shape[0] * 3 * tensor_dim self.shape = (n_rows, n_rows) self.mat = scipy.sparse.csr_matrix((vals, (rows, cols)), shape = self.shape)
def traction_continuity_constraints(pts, surface_tris, fault_tris, tensor_dim=3): from tectosaur.constraints import ConstraintEQ, Term from tectosaur.constraint_builders import find_touching_pts from tectosaur.util.geometry import unscaled_normals n_surf_tris = surface_tris.shape[0] n_fault_tris = fault_tris.shape[0] touching_pt = find_touching_pts(surface_tris) if fault_tris.shape[0] > 0: fault_touching_pt = find_touching_pts(fault_tris) else: fault_touching_pt = [] fault_touching_pt.extend( [[] for i in range(len(touching_pt) - len(fault_touching_pt))]) constraints = [] normals = unscaled_normals(pts[surface_tris]) normals /= np.linalg.norm(normals, axis=1)[:, np.newaxis] jj = 0 for i, tpt in enumerate(touching_pt): if len(tpt) == 0: continue for independent_idx in range(len(tpt)): independent = tpt[independent_idx] independent_tri_idx = independent[0] independent_tri = surface_tris[independent_tri_idx] for dependent_idx in range(independent_idx + 1, len(tpt)): dependent = tpt[dependent_idx] dependent_tri_idx = dependent[0] dependent_tri = surface_tris[dependent_tri_idx] n1 = normals[independent_tri_idx] n2 = normals[dependent_tri_idx] same_plane = np.all(np.abs(n1 - n2) < 1e-6) if not same_plane: jj += 1 print('not same plane', jj, n1, n2) continue # Check for anything that touches across the fault. crosses = (fault_tris.shape[0] > 0 and check_if_crosses_fault( independent_tri, dependent_tri, fault_touching_pt, fault_tris)) if crosses: continue for d in range(tensor_dim): independent_dof = (independent_tri_idx * 3 + independent[1]) * tensor_dim + d dependent_dof = (dependent_tri_idx * 3 + dependent[1]) * tensor_dim + d if dependent_dof <= independent_dof: continue diff = 0.0 constraints.append( ConstraintEQ([ Term(1.0, dependent_dof), Term(-1.0, independent_dof) ], diff)) return constraints
def traction_admissibility_constraints(pts, tris, fault_start_idx): # At each vertex, there should be three remaining degrees of freedom. # Initially, there are n_tris*3 degrees of freedom. # So, we need (n_tris-1)*3 constraints. touching_pt = find_touching_pts(tris) ns = normalize(unscaled_normals(pts[tris])) side = get_side_of_fault(pts, tris, fault_start_idx) continuity_cs = [] admissibility_cs = [] for tpt in touching_pt: if len(tpt) == 0: continue # Separate the triangles touching at the vertex into a groups # by the normal vectors for each triangle. normal_groups = [] for i in range(len(tpt)): tri_idx = tpt[i][0] n = ns[tri_idx] joined = False for j in range(len(normal_groups)): if np.allclose(normal_groups[j][0], n): tri_idx2 = tpt[normal_groups[j][1][0]][0] side1 = side[tri_idx] side2 = side[tri_idx2] crosses = (side1 != side2) and (side1 != 0) and (side2 != 0) fault_tri_idx = None # if crosses: # continue normal_groups[j][1].append(i) joined = True break if not joined: normal_groups.append((n, [i])) # Continuity within normal group for i in range(len(normal_groups)): group = normal_groups[i][1] independent_idx = group[0] independent = tpt[independent_idx] independent_tri_idx = independent[0] independent_corner_idx = independent[1] independent_dof_start = independent_tri_idx * 9 + independent_corner_idx * 3 for j in range(1, len(group)): dependent_idx = group[j] dependent = tpt[dependent_idx] dependent_tri_idx = dependent[0] dependent_corner_idx = dependent[1] dependent_dof_start = dependent_tri_idx * 9 + dependent_corner_idx * 3 for d in range(3): terms = [ Term(1.0, dependent_dof_start + d), Term(-1.0, independent_dof_start + d) ] continuity_cs.append(ConstraintEQ(terms, 0.0)) if len(normal_groups) == 1: # Only continuity needed! continue # assert(len(normal_groups) == 2) # Add constant stress constraints for i in range(len(normal_groups)): tpt_idx1 = normal_groups[i][1][0] tri_idx1 = tpt[tpt_idx1][0] corner_idx1 = tpt[tpt_idx1][1] tri1 = pts[tris[tri_idx1]] tri_data1 = (tri1, tri_idx1, corner_idx1) for j in range(i + 1, len(normal_groups)): tpt_idx2 = normal_groups[j][1][0] tri_idx2 = tpt[tpt_idx2][0] # print(tri_idx1, tri_idx2) corner_idx2 = tpt[tpt_idx2][1] tri2 = pts[tris[tri_idx2]] tri_data2 = (tri2, tri_idx2, corner_idx2) # for c in new_cs: # print(', '.join(['(' + str(t.val) + ',' + str(t.dof) + ')' for t in c.terms]) + ' rhs: ' + str(c.rhs)) admissibility_cs.append( constant_stress_constraint(tri_data1, tri_data2)) admissibility_cs.append(equilibrium_constraint(tri_data1)) admissibility_cs.append(equilibrium_constraint(tri_data2)) return continuity_cs, admissibility_cs
def tri_normal_info(m): unscaled_tri_normals = unscaled_normals(m.pts[m.tris]) tri_size = np.linalg.norm(unscaled_tri_normals, axis=1) tri_normals = unscaled_tri_normals / tri_size[:, np.newaxis] return unscaled_tri_normals, tri_size, tri_normals