def inverse(bmat): ''' Inverse of a linear combination of Hs norms. We very strictly enforce the form of sum_j alpha_j H^{s_j} ''' if isinstance(bmat, InterpolationMatrix): return bmat**-1 if isinstance(bmat, block_utils.VectorizedOperator): return block_utils.VectorizedOperator(inverse(bmat.bmat), bmat.W) # Does it satisfy the definittion assert is_well_defined(bmat) # Try to see if sombody computes the eigenvalues lmbda, U = extract_attributes(bmat, ('lmbda', 'U')) # Do it your self if U is None or lmbda is None: A, M = extract_attributes(bmat, ('A', 'M')) lmbda, U = eigh(A.array(), M.array()) diagonal = np.zeros_like(lmbda) for alpha, s in collect(bmat): diagonal[:] += alpha * (lmbda**s) # Invert diagonal[:] = 1. / diagonal array = U.dot(np.diag(diagonal).dot(U.T)) return numpy_to_petsc(array)
def inverse(bmat): ''' Inverse of a linear combination of Hs norms. We very strictly enforce the form of sum_j alpha_j H^{s_j} ''' if isinstance(bmat, InterpolationMatrix): return bmat**-1 if isinstance(bmat, block_utils.VectorizedOperator): return block_utils.VectorizedOperator(inverse(bmat.bmat), bmat.W) # Does it satisfy the definittion assert is_well_defined(bmat) # Try to see if sombody computes the eigenvalues lmbda, U = extract_attributes(bmat, ('lmbda', 'U')) # Do it your self if U is None or lmbda is None: A, M = extract_attributes(bmat, ('A', 'M')) lmbda, U = eigh(A.array(), M.array()) diagonal = np.zeros_like(lmbda) for alpha, s in collect(bmat): diagonal[:] += alpha*(lmbda**s) # Invert diagonal[:] = 1./diagonal array = U.dot(np.diag(diagonal).dot(U.T)) return numpy_to_petsc(array)
def as_block(monolithic, blocks): '''Turn monolithic operator into block-structured one with indices specified in blocks''' comm = mpi_comm_world() # We want list of PETSc.IS-es elm_type, = element_types(blocks) if elm_type is FunctionSpace: offsets = np.cumsum(np.r_[0, [Wi.dim() for Wi in blocks]]) idx = [] for first, last in zip(offsets[:-1], offsets[1:]): idx.append(PETSc.IS().createStride(last - first, first, 1)) return as_block(monolithic, idx) elif elm_type in (list, np.ndarray): return as_block(monolithic, [ PETSc.IS().createGeneral(np.asarray(block, dtype='int32')) for block in blocks ]) assert elm_type is PETSc.IS # Break up Vector to block-vec if isinstance(monolithic, (GenericVector, Vector)): return as_block(as_backend_type(monolithic).vec(), blocks) if isinstance(monolithic, (GenericMatrix, Matrix)): return as_block(as_backend_type(monolithic).mat(), blocks) if isinstance(monolithic, PETSc.Vec): b = [ PETSc.Vec().createWithArray(monolithic.getValues(block), comm=comm) for block in blocks ] for bi in b: bi.assemblyBegin() bi.assemblyEnd() return block_vec(list(map(PETScVector, b))) # Otherwise we have a Matrix try: monolithic.getSubMatrix A = [[ PETScMatrix(monolithic.getSubMatrix(block_row, block_col)) for block_col in blocks ] for block_row in blocks] # NOTE: 3.8+ does not ahve getSubMatrix, there is getLocalSubMatrix # but cannot get that to work - petsc error 73. So for now everything # is done with scipy except AttributeError: monolithic = csr_matrix(monolithic.getValuesCSR()[::-1], shape=monolithic.size) A = [[ numpy_to_petsc(monolithic[block_row.array, :][:, block_col.array]) for block_col in blocks ] for block_row in blocks] # Done return block_mat(A)
def uniform_extension_matrix(V, EV): ''' Map vector of coeficients of V(over 1d domain) to vector of coefficients of EV(over 2d domain). The spaces need to use the same element type. ''' gdim = V.mesh().geometry().dim() assert gdim == EV.mesh().geometry().dim() # For Vector and Tensor elements more than 1 degree of freedom is # associated with the same geometric point. It is therefore cheaper # to compute the mapping based only on the scalar/one subspace considerations. is_tensor_elm = isinstance(V.ufl_element(), (df.VectorElement, df.TensorElement)) # Base on scalar if is_tensor_elm: V_dofs_x = V.sub(0).collapse().tabulate_dof_coordinates().reshape((-1, gdim)) EV_dofs_x = EV.sub(0).collapse().tabulate_dof_coordinates().reshape((-1, gdim)) # Otherwise 'scalar', (Hdiv element belong here as well) else: V_dofs_x = V.tabulate_dof_coordinates().reshape((V.dim(), gdim)) EV_dofs_x = EV.tabulate_dof_coordinates().reshape((EV.dim(), gdim)) # Compute distance from every EV dof(row) to every V dof(column) lookup = cdist(EV_dofs_x, V_dofs_x) # Make sure the two domains do not intersect assert np.linalg.norm(lookup, np.inf) > 0 # Now get the closest dof to E columns = np.argmin(lookup, axis=1) # Every scalar can be used used to set all the components if is_tensor_elm: shift = V.dim()/len(V_dofs_x) component_idx = np.arange(shift) # shift*dof + components columns = (shift*np.array([columns]).T + component_idx).flatten() # As csr (1 col per row) values = np.ones_like(columns) rows = np.arange(EV.dim()+1) E = csr_matrix((values, columns, rows), shape=(EV.dim(), V.dim())) return numpy_to_petsc(E)
def apply_bc(A, b, bcs, diag_val=1.): ''' Apply block boundary conditions to block system A, b ''' if not any(bcs): return A, b # Allow for A, b be simple matrices. To proceed we wrap them as # block objects has_wrapped_A = False if not isinstance(A, block_mat): A = block_mat([[A]]) has_wrapped_A = True if b is None: b = A.create_vec() if not isinstance(b, block_vec): assert has_wrapped_A b = block_vec([b]) bcs = [bcs] # block boundary conditions is a list with bcs for each block of A, b assert len(A) == len(b) == len(bcs) bcs_ = [] for bc in bcs: assert isinstance(bc, (DirichletBC, list)) if isinstance(bc, DirichletBC): bcs_.append([bc]) else: bcs_.append(bc) bcs = bcs_ if not bcs or not any(bcs): return A, b # Obtain a monolithic matrix AA, bb = map(convert, (A, b)) # PETSc guys AA, bb = as_backend_type(AA).mat(), as_backend_type(bb).vec() # We want to make a monotlithic matrix corresponding to function sp ace # where the spaces are serialized # Break apart for block offsets = [0] for bi in b: offsets.append(offsets[-1] + bi.size()) rows = [] x_values = [] # Each bc in the group has dofs numbered only wrt to its space. # We're after global numbering for shift, bcs_sub in zip(offsets, bcs): for bc in bcs_sub: # NOTE: bcs can be a dict or DirichletBC in which case we extract # the dict if isinstance(bc, DirichletBC): bc = bc.get_boundary_values() # Dofs and values for rhs rows.extend(shift + np.array(bc.keys(), dtype='int32')) x_values.extend(bc.values()) rows = np.hstack(rows) x_values = np.array(x_values) x = bb.copy() x.zeroEntries() x.setValues(rows, x_values) # Apply to monolithic len(rows) and AA.zeroRowsColumns(rows, diag=diag_val, x=x, b=bb) blocks = [] for first, last in zip(offsets[:-1], offsets[1:]): blocks.append(PETSc.IS().createStride(last-first, first, 1)) # Reasamble comm = mpi_comm_world() b = [PETSc.Vec().createWithArray(bb.getValues(block), comm=comm) for block in blocks] for bi in b: bi.assemblyBegin() bi.assemblyEnd() b = block_vec(map(PETScVector, b)) # PETSc 3.7.x try: AA.getSubMatrix A = [[PETScMatrix(AA.getSubMatrix(block_row, block_col)) for block_col in blocks] for block_row in blocks] # NOTE: 3.8+ does not ahve getSubMatrix, there is getLocalSubMatrix # but cannot get that to work - petsc error 73. So for now everything # is done with scipy except AttributeError: AA = csr_matrix(AA.getValuesCSR()[::-1], shape=AA.size) A = [[numpy_to_petsc(AA[block_row.array, :][:, block_col.array]) for block_col in blocks] for block_row in blocks] # Block mat A = block_mat(A) if has_wrapped_A: return A[0][0], b[0] return A, b