def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # None means all if tag_data is None: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set((0, ))) trace_mesh_subdomains, tags = tag_data # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) except (AssertionError, IndexError): warning('Using non-conforming trace') # So non-conforming matrix returns PETSc.Mat return nonconforming_trace_mat(V, TV) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions # of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Only look at tagged cells trace_cells = itertools.chain(*[ itertools.imap(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ]) # Rows visited_dofs = [False] * TV.dim() # Column values dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(TV, V) as mat: for trace_cell in trace_cells: # We might TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) for local_T, dof_T in enumerate(trace_dofs): if visited_dofs[dof_T]: continue else: visited_dofs[dof_T] = True # Define trace dof TV_dof.dof = local_T # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = TV_dof.eval(V_basis_f) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') # Insert mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) return mat
def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # None means all if tag_data is None: try: marking_function = trace_mesh.marking_function tag_data = (marking_function, set(marking_function.array())) except AttributeError: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set( (0, ))) trace_mesh_subdomains, tags = tag_data # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) except (AssertionError, IndexError): warning('Using non-conforming trace') # So non-conforming matrix returns PETSc.Mat return nonconforming_trace_mat(V, TV) if V.ufl_element().family() == 'HDiv Trace': assert V.ufl_element().degree() == 0 # In this case return DLT_trace_mat(V, TV, trace_mesh=trace_mesh, tag_data=tag_data) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Only look at tagged cells trace_cells = list( itertools.chain(*[ map(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ])) ndofs_elm, nbasis_elm = TV_dof.elm.space_dimension( ), V_basis_f.elm.space_dimension() local_values = np.zeros((nbasis_elm, ndofs_elm)) if len(trace_cells) > 10_000: print(f'Trace mat {TV.ufl_element()} -> {V.ufl_element()}') trace_cells = tqdm.tqdm(trace_cells, total=len(trace_cells)) rows, cols, values = [], [], [] # DG spaces don't share rows between cells so we take advantage of # this in special branch if TV.ufl_element().family() == 'Discontinuous Lagrange': for trace_cell in trace_cells: TV_dof.cell = trace_cell # Many rows at once trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell # Columns for the rows dofs = dmap.cell_dofs(cell) for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local # Get all rows at once local_values[local][:] = TV_dof.eval_dofs(V_basis_f) # Indices for the filled piece rows_ = np.tile(trace_dofs, nbasis_elm) cols_ = np.repeat(dofs, ndofs_elm) rows.extend(rows_) cols.extend(cols_) values.extend(local_values.flat) # FIXME: Othewise we need to take care of duplicate entrieselse: else: needs_fill = np.ones(TV.dim(), dtype=bool) for trace_cell in trace_cells: TV_dof.cell = trace_cell # Many rows at once trace_dofs = Tdmap.cell_dofs(trace_cell) # Don't add duplicates unseen = needs_fill[trace_dofs] # Some will be true and # For the future needs_fill[trace_dofs[unseen]] = False # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell # Columns for the rows dofs = dmap.cell_dofs(cell) for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local # Get all rows at once local_values[local][:] = TV_dof.eval_dofs(V_basis_f) # Indices for the filled piece rows_ = np.tile(trace_dofs[unseen], nbasis_elm) cols_ = np.repeat(dofs, sum(unseen)) rows.extend(rows_) cols.extend(cols_) values.extend(local_values[:, unseen].flat) mat = csr_matrix((values, (rows, cols)), shape=(TV.dim(), V.dim())) return PETSc.Mat().createAIJ(comm=PETSc.COMM_WORLD, size=mat.shape, csr=(mat.indptr, mat.indices, mat.data))
for n in (8, 16, 32): mesh = UnitSquareMesh(*(n, ) * 2) mesh_fine = UnitSquareMesh(*(3 * n, ) * 2) cell_f = MeshFunction('size_t', mesh_fine, 1, 0) CompiledSubDomain('near(x[0], 0)').mark(cell_f, 1) bmesh = EmbeddedMesh(cell_f, 1) V = VectorFunctionSpace(mesh, 'DG', 1) bar = Expression(('x[0]', 'x[1]'), degree=1) v = interpolate(bar, V) Q = VectorFunctionSpace(bmesh, 'DG', 1) T = PETScMatrix(nonconforming_trace_mat(V, Q)) v = interpolate(bar, V) q = Function(Q, T * v.vector()) L = inner(bar[0] - q[0], bar[0] - q[0]) * dx print sqrt(abs(assemble(L))) L = inner(bar[1] - q[1], bar[1] - q[1]) * dx print sqrt(abs(assemble(L))) q0, q1 = q.split(deepcopy=True) x = bmesh.coordinates() y = np.array([q1(xi) for xi in x]) x = x[:, 1]
def trace_mat_no_restrict(V, TV, trace_mesh=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh) except AssertionError: warning('Using non-conforming trace') return nonconforming_trace_mat(V, TV) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions # of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Rows visited_dofs = [False] * TV.dim() # Column values dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(TV, V) as mat: for trace_cell in range(TV.mesh().num_cells()): TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) for local_T, dof_T in enumerate(trace_dofs): if visited_dofs[dof_T]: continue else: visited_dofs[dof_T] = True # Define trace dof TV_dof.dof = local_T # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = TV_dof.eval(V_basis_f) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') # Insert mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) return mat
def trace_mat_no_restrict(V, TV, trace_mesh=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh) except AssertionError: warning('Using non-conforming trace') return nonconforming_trace_mat(V, TV) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim+1) f2c = mesh.topology()(fdim, fdim+1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions # of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Rows visited_dofs = [False]*TV.dim() # Column values dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(TV, V) as mat: for trace_cell in range(TV.mesh().num_cells()): TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) for local_T, dof_T in enumerate(trace_dofs): if visited_dofs[dof_T]: continue else: visited_dofs[dof_T] = True # Define trace dof TV_dof.dof = local_T # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = TV_dof.eval(V_basis_f) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') # Insert mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) return mat