def injection_matrix(Vc, Vf, fine_mesh, data): '''Injection mapping from Vc to Vf''' mesh_c = Vc.mesh() assert fine_mesh.id() == Vf.mesh().id() mesh_f = Vf.mesh() if data['not_nested_method'] == 'interpolate': return df.PETScDMCollection.create_transfer_matrix(Vc, Vf) elif data['not_nested_method'] == 'project': raise ValueError('Missing projection') # Fallback to our interpolate with lookup, which, however is slower # to `create_transfer_matrix` tdim = mesh_f.topology().dim() # Refine was used to create it keys, fine_to_coarse = list( zip(*list(fine_mesh.parent_entity_map[mesh_c.id()][tdim].items()))) fine_to_coarse = np.array(fine_to_coarse, dtype='uintp') fine_to_coarse[np.argsort(keys)] = fine_to_coarse # The idea is to evaluate Vf's degrees of freedom at basis functions of Vc fdmap = Vf.dofmap() Vf_dof = DegreeOfFreedom(Vf) cdmap = Vc.dofmap() Vc_basis_f = FEBasisFunction(Vc) # Column values visited_rows = [False] * Vf.dim() row_values = np.zeros(Vc_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(Vf, Vc) as mat: for f_cell, c_cell in enumerate(fine_to_coarse): Vc_basis_f.cell = c_cell # These are the colums coarse_dofs = cdmap.cell_dofs(c_cell) Vf_dof.cell = f_cell fine_dofs = fdmap.cell_dofs(f_cell) for local, dof in enumerate(fine_dofs): if visited_rows[dof]: continue else: visited_rows[dof] = True Vf_dof.dof = local # Evaluete coarse basis foos here for local_c, dof_c in enumerate(coarse_dofs): Vc_basis_f.dof = local_c row_values[local_c] = Vf_dof.eval(Vc_basis_f) # Insert mat.setValues([dof], coarse_dofs, row_values, PETSc.InsertMode.INSERT_VALUES) return PETScMatrix(mat)
def restriction_matrix(V, TV, rmesh): '''The first cell connected to the facet gets to set the values of TV''' assert TV.mesh().id() == rmesh.id() mesh = V.mesh() tdim = mesh.topology().dim() # Let's get the mapping or cell of TV mesh to V mesh cells mapping = rmesh.parent_entity_map[mesh.id()][tdim] # 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) # The corresponding cell in V mesh cell = mapping[trace_cell] 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 restriction_matrix(V, TV, rmesh): '''The first cell connected to the facet gets to set the values of TV''' assert TV.mesh().id() == rmesh.id() mesh = V.mesh() tdim = mesh.topology().dim() # Let's get the mapping or cell of TV mesh to V mesh cells mapping = rmesh.parent_entity_map[mesh.id()][tdim] # 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) # The corresponding cell in V mesh cell = mapping[trace_cell] 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 injection_matrix(Vc, Vf): '''Injection mapping from Vc to Vf''' mesh_c = Vc.mesh() mesh_f = Vf.mesh() assert mesh_f.has_parent() and mesh_c.has_child() assert mesh_f.parent().id() == mesh_c.id() fine_to_coarse = mesh_f.data().array('parent_cell', mesh_f.topology().dim()) # The idea is to evaluate Vf's degrees of freedom at basis functions of Vc fdmap = Vf.dofmap() Vf_dof = DegreeOfFreedom(Vf) cdmap = Vc.dofmap() Vc_basis_f = FEBasisFunction(Vc) # Column values visited_rows = [False] * Vf.dim() row_values = np.zeros(Vc_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(Vf, Vc) as mat: for f_cell, c_cell in enumerate(fine_to_coarse): Vc_basis_f.cell = c_cell # These are the colums coarse_dofs = cdmap.cell_dofs(c_cell) Vf_dof.cell = f_cell fine_dofs = fdmap.cell_dofs(f_cell) for local, dof in enumerate(fine_dofs): if visited_rows[dof]: continue else: visited_rows[dof] = True Vf_dof.dof = local # Evaluete coarse basis foos here for local_c, dof_c in enumerate(coarse_dofs): Vc_basis_f.dof = local_c row_values[local_c] = Vf_dof.eval(Vc_basis_f) # Insert mat.setValues([dof], coarse_dofs, row_values, PETSc.InsertMode.INSERT_VALUES) # Transpose return mat
def interpolation_mat(V, Q): ''' Matrix representation of interpolation operator from V to Q ''' # Compatibility of spaces assert V.dolfin_element().value_rank() == Q.dolfin_element().value_rank() assert V.ufl_element().value_shape() == Q.ufl_element().value_shape() # We assume that the spaces are constructed on the same mesh assert V.mesh().id() == Q.mesh().id() # The idea is to evaluate Q's degrees of freedom at basis functions of V V_dm = V.dofmap() V_basis_f = FEBasisFunction(V) Q_dm = Q.dofmap() Q_dof = DegreeOfFreedom(Q) visited_rows = np.zeros(Q.dim(), dtype=bool) # Column values for row column_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(Q, V) as mat: for cell in xrange(V.mesh().num_cells()): Q_dof.cell = cell V_basis_f.cell = cell cell_rows = Q_dm.cell_dofs(cell) column_indices = np.array(V_dm.cell_dofs(cell), dtype='int32') for local_row, row in enumerate(cell_rows): if visited_rows[row]: continue visited_rows[row] = True # Define dof Q_dof.dof = local_row # Eval at V basis functions for local_col, col in enumerate(column_indices): # Set which basis foo V_basis_f.dof = local_col column_values[local_col] = Q_dof.eval(V_basis_f) # Can fill the matrix now mat.setValues([row], column_indices, column_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: 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_two_restrict(V, TV, restriction, normal, trace_mesh=None): ''' Compute the trace values using avg/jump restriction. A + plus is the one for which the vector cell.midpoint - facet.midpoint agrees in orientation with the normal on the facet. ''' mesh = V.mesh() fdim = mesh.topology().dim() - 1 if trace_mesh is None: trace_mesh = TV.mesh() # Init/extract entity map assert get_entity_map(mesh, trace_mesh) # 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) # We define avg as sum(+, -)/2 and jump as sum(+, neg(-)) operator_pieces = { 'avg': (lambda x: x / 2, lambda x: x / 2), 'jump': (lambda x: x, lambda x: -x) }[restriction] gdim = mesh.geometry().dim() # 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(trace_mesh.num_cells()): TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here facet_cells = f2c(mapping[trace_cell]) assert 0 < len(facet_cells) < 3 # Ignore boundary facets if len(facet_cells) == 1: facet_cells = [facet_cells[0]] modifiers = (lambda x: x, ) # Do nothing # Search which cell has the right sign else: signs = [None, None] # Order such that '+' is first t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim] mp = Cell(mesh, facet_cells[0]).midpoint().array()[:gdim] sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-' # Need to flip if sign == '-': facet_cells = facet_cells[::-1] # As requested modifiers = operator_pieces 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 # Two sweeps to set the values in the row ADD_VALUES = False for modify, cell in zip(modifiers, facet_cells): V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = modify(TV_dof.eval(V_basis_f)) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') if not ADD_VALUES: mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) ADD_VALUES = True #print 'setting', dof_T, col_indices, dof_values else: mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.ADD_VALUES) #print 'adding', dof_T, col_indices, dof_values return mat
def trace_mat_one_restrict(V, TV, restriction, normal, trace_mesh=None, tag_data=None): ''' Compute the trace values using +/- restriction. A + plus is the one for which the vector cell.midpoint - facet.midpoint agrees in orientation with the normal on the facet. ''' mesh = V.mesh() fdim = mesh.topology().dim() - 1 if trace_mesh is None: trace_mesh = TV.mesh() # 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 # Only look at tagged cells trace_cells = itertools.chain(*[ itertools.imap(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ]) # Init/extract entity map assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) # 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) gdim = mesh.geometry().dim() # 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: TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here facet_cells = f2c(mapping[trace_cell]) assert 0 < len(facet_cells) < 3 # Ignore boundary facets if len(facet_cells) == 1: cell = facet_cells[0] # Search which cell has the right sign else: signs = [] for fcell in facet_cells: t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim] mp = Cell(mesh, fcell).midpoint().array()[:gdim] sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-' signs.append(sign) cell = facet_cells[signs.index(restriction)] 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 assert get_entity_map(mesh, trace_mesh) # 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 nonconforming_trace_mat(V, T): ''' Matrix taking function f from d dim space V to g in (d-1) space T. T(f) ~ g should hold. ''' # For this to work I only make sure that function values are the same assert V.ufl_element().value_shape() == T.ufl_element().value_shape() # I want to evaluate T degrees of freedom at V basis functions, i.e. # L^T_k{phi^V_l}. The picture is # # ------ # \ /\ # ===\==/==\====T # \/----\ # # and thus is assume that each dof of T space (row) will involve # collisions with several cells/basis function of V space. However # here we only snap to the first one mesh = V.mesh() # The (d-1)trace mesh tree = mesh.bounding_box_tree() limit = mesh.num_entities_global(mesh.topology().dim()) Tdm = T.dofmap() elm_T = T.element() # Colliding cells with trace dofs collisions = [] for Tdof_x in T.tabulate_dof_coordinates().reshape((T.dim(), -1)): c = tree.compute_first_entity_collision(df.Point(*Tdof_x)) # Contained? c >= limit and df.warning('Some colliding cells not found') collisions.append(c) # So we fill rows by checking basis functions of on the isected cells Vdm = V.dofmap() elm_V = V.element() V_basis_function = FEBasisFunction(V) T_degree_of_freedom = DegreeOfFreedom(T) X_T = T.tabulate_dof_coordinates().reshape((T.dim(), -1)) X_V = V.tabulate_dof_coordinates().reshape((V.dim(), -1)) visited_dofs = np.zeros(T.dim(), dtype=bool) col_values = np.zeros(V_basis_function.elm.space_dimension(), dtype='double') with petsc_serial_matrix(T, V) as mat: for Tcell in range(T.mesh().num_cells()): # Set for this cell T_degree_of_freedom.cell = Tcell Tdofs = Tdm.cell_dofs(Tcell) for local_T, Tdof in enumerate(Tdofs): # Seen the row? if visited_dofs[Tdof]: continue visited_dofs[Tdof] = True # Set to current dof T_degree_of_freedom.dof = local_T # Now all the V cells and their basis functions c = collisions[Tdof] # If we have no reasonable cell leave the row empty if c >= limit: continue # Set the dof cell V_basis_function.cell = c Vdofs = np.array(Vdm.cell_dofs(c), dtype='int32') # These are columns # Fill column for local_V, Vdof in enumerate(Vdofs): # Set as basis_function V_basis_function.dof = local_V # Evaluate trace dof at basis function dof_value = T_degree_of_freedom.eval(V_basis_function) col_values[local_V] = dof_value mat.setValues([Tdof], Vdofs, col_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))
def nonconforming_trace_mat(V, T): ''' Matrix taking function f from d dim space V to g in (d-1) space T. T(f) ~ g should hold. ''' # For this to work I only make sure that function values are the same assert V.dolfin_element().value_rank() == T.dolfin_element().value_rank() assert V.ufl_element().value_shape() == T.ufl_element().value_shape() # I want to evaluate T degrees of freedom at V basis functions, i.e. # L^T_k{phi^V_l}. The picture is # # ------ # \ /\ # ===\==/==\====T # \/----\ # # and thus is assume that each dof of T space (row) will involve # collisions with several cells/basis function of V space mesh = V.mesh() # The (d-1)trace mesh tree = mesh.bounding_box_tree() limit = mesh.topology().size_global(mesh.topology().dim()) Tdm = T.dofmap() elm_T = T.element() # Colliding cells with trace dofs collisions = [] for Tdof_x in T.tabulate_dof_coordinates().reshape((T.dim(), -1)): cs = tree.compute_entity_collisions(Point(*Tdof_x)) if any(c >= limit for c in cs): warning('Some colliding cells not found') cs = filter(lambda c: c < limit, cs) collisions.append(cs) # So we fill rows by checking basis functions of on the isected cells Vdm = V.dofmap() elm_V = V.element() V_basis_function = FEBasisFunction(V) T_degree_of_freedom = DegreeOfFreedom(T) visited_dofs = [False]*T.dim() with petsc_serial_matrix(T, V) as mat: for Tcell in range(T.mesh().num_cells()): # Set for this cell T_degree_of_freedom.cell = Tcell Tdofs = Tdm.cell_dofs(Tcell) for local_T, Tdof in enumerate(Tdofs): # Seen the row? if visited_dofs[Tdof]: continue visited_dofs[Tdof] = True # Set to current dof T_degree_of_freedom.dof = local_T col_indices, col_values = [], [] # Now all the V cells and their basis functions for c in collisions[Tdof]: # Set the dof cell V_basis_function.cell = c Vdofs = Vdm.cell_dofs(c) # Columns for local_V, Vdof in enumerate(Vdofs): if Vdof in col_indices: continue # Set as basis_function V_basis_function.dof = local_V # Evaluate trace dof at basis function dof_value = T_degree_of_freedom.eval(V_basis_function) col_indices.append(Vdof) col_values.append(dof_value) # Can fill the matrix row col_indices = np.array(col_indices, dtype='int32') col_values = np.array(col_values) mat.setValues([Tdof], col_indices, col_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
def trace_mat_two_restrict(V, TV, restriction, normal, trace_mesh=None): ''' Compute the trace values using avg/jump restriction. A + plus is the one for which the vector cell.midpoint - facet.midpoint agrees in orientation with the normal on the facet. ''' mesh = V.mesh() fdim = mesh.topology().dim() - 1 if trace_mesh is None: trace_mesh = TV.mesh() # Init/extract entity map assert get_entity_map(mesh, trace_mesh) # 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) # We define avg as sum(+, -)/2 and jump as sum(+, neg(-)) operator_pieces = {'avg': (lambda x: x/2, lambda x: x/2), 'jump': (lambda x: x, lambda x: -x)}[restriction] gdim = mesh.geometry().dim() # 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(trace_mesh.num_cells()): TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here facet_cells = f2c(mapping[trace_cell]) assert 0 < len(facet_cells) < 3 # Ignore boundary facets if len(facet_cells) == 1: facet_cells = [facet_cells[0]] modifiers = (lambda x: x, ) # Do nothing # Search which cell has the right sign else: signs = [None, None] # Order such that '+' is first t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim] mp = Cell(mesh, facet_cells[0]).midpoint().array()[:gdim] sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-' # Need to flip if sign == '-': facet_cells = facet_cells[::-1] # As requested modifiers = operator_pieces 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 # Two sweeps to set the values in the row ADD_VALUES = False for modify, cell in zip(modifiers, facet_cells): V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = modify(TV_dof.eval(V_basis_f)) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') if not ADD_VALUES: mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) ADD_VALUES = True #print 'setting', dof_T, col_indices, dof_values else: mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.ADD_VALUES) #print 'adding', dof_T, col_indices, dof_values return mat
def trace_mat_one_restrict(V, TV, restriction, normal, trace_mesh=None): ''' Compute the trace values using +/- restriction. A + plus is the one for which the vector cell.midpoint - facet.midpoint agrees in orientation with the normal on the facet. ''' mesh = V.mesh() fdim = mesh.topology().dim() - 1 if trace_mesh is None: trace_mesh = TV.mesh() # Init/extract entity map assert get_entity_map(mesh, trace_mesh) # 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) gdim = mesh.geometry().dim() # 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(trace_mesh.num_cells()): TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here facet_cells = f2c(mapping[trace_cell]) assert 0 < len(facet_cells) < 3 # Ignore boundary facets if len(facet_cells) == 1: cell = facet_cells[0] # Search which cell has the right sign else: signs = [] for fcell in facet_cells: t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim] mp = Cell(mesh, fcell).midpoint().array()[:gdim] sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-' signs.append(sign) cell = facet_cells[signs.index(restriction)] 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