def _jacobian_matrix_assemble(self, jacobian_matrix_input: GenericMatrix, petsc_jacobian: PETSc.Mat): self.jacobian_matrix = PETScMatrix(petsc_jacobian) self.jacobian_matrix.zero() self.jacobian_matrix += jacobian_matrix_input # Make sure to keep nonzero pattern, as dolfin does by default, because this option is apparently # not preserved by the sum petsc_jacobian.setOption(PETSc.Mat.Option.KEEP_NONZERO_PATTERN, True)
def J(self, x: PETSc.Vec, A: PETSc.Mat): """Assemble the Jacobian matrix. Args: x: The vector containing the latest solution """ A.zeroEntries() assemble_matrix(A, self._a, self.bcs) A.assemble()
def J(self, snes, x: PETSc.Vec, A: PETSc.Mat, P: PETSc.Mat): """Assemble the Jacobian matrix. Parameters ========== x: Vector containing the latest solution. A: Matrix to assemble the Jacobian into. """ A.zeroEntries() assemble_matrix(A, self.J_form, self.bcs) A.assemble()
def J(self, x: PETSc.Vec, A: PETSc.Mat): """Assemble the Jacobian matrix. Parameters ---------- x The vector containing the latest solution A The matrix to assemble the Jacobian into """ A.zeroEntries() assemble_matrix(A, self._a, self.bcs) A.assemble()
def restrict_matrix(self, A: PETSc.Mat): # Fetching IS only for owned dofs # Ghost dofs would get the same global index which would result in # duplicate global indices in global IS local_isrow = PETSc.IS(self.comm).createGeneral( self.bglobal_dofs_mat_stacked) global_isrow = A.getLGMap()[0].applyIS(local_isrow) subA = A.createSubMatrix(isrow=global_isrow, iscol=global_isrow) subA.assemble() return subA
def _(A: PETSc.Mat, a: typing.List[typing.List[typing.Union[Form, cpp.fem.Form]]], bcs: typing.List[DirichletBC] = [], diagonal: float = 1.0) -> PETSc.Mat: """Assemble bilinear forms into matrix""" _a = _create_cpp_form(a) V = _extract_function_spaces(_a) is_rows = cpp.la.create_petsc_index_sets([(Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[0]]) is_cols = cpp.la.create_petsc_index_sets([(Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[1]]) # Assemble form for i, a_row in enumerate(_a): for j, a_sub in enumerate(a_row): if a_sub is not None: Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j]) cpp.fem.assemble_matrix_petsc_unrolled(Asub, a_sub, bcs) A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub) # Flush to enable switch from add to set in the matrix A.assemble(PETSc.Mat.AssemblyType.FLUSH) # Set diagonal for i, a_row in enumerate(_a): for j, a_sub in enumerate(a_row): if a_sub is not None: Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j]) if a_sub.function_spaces[0].id == a_sub.function_spaces[1].id: cpp.fem.insert_diagonal(Asub, a_sub.function_spaces[0], bcs, diagonal) A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub) return A
def _(A: PETSc.Mat, a: typing.Union[Form, cpp.fem.Form], bcs: typing.List[DirichletBC] = [], diagonal: float = 1.0) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not finalised, i.e. ghost values are not accumulated. """ _a = _create_cpp_form(a) cpp.fem.assemble_matrix_petsc(A, _a, bcs) if _a.function_spaces[0].id == _a.function_spaces[1].id: A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH) A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH) cpp.fem.insert_diagonal(A, _a.function_spaces[0], bcs, diagonal) return A
def assemble_matrix_nest( A: _PETSc.Mat, a: Sequence[Sequence[_fem.FormMetaClass]], constraints: Sequence[MultiPointConstraint], bcs: Sequence[_fem.DirichletBCMetaClass] = [], diagval: _PETSc.ScalarType = 1): """ Assemble a compiled DOLFINx bilinear form into a PETSc matrix of type "nest" with corresponding multi point constraints and Dirichlet boundary conditions. Parameters ---------- a The compiled bilinear variational form provided in a rank 2 list constraints An ordered list of multi point constraints bcs Sequence of Dirichlet boundary conditions diagval Value to set on the diagonal of the matrix (Default 1) A PETSc matrix to assemble into """ for i, a_row in enumerate(a): for j, a_block in enumerate(a_row): if a_block is not None: Asub = A.getNestSubMatrix(i, j) assemble_matrix( a_block, (constraints[i], constraints[j]), bcs=bcs, diagval=diagval, A=Asub)
def _(A: PETSc.Mat, a: typing.List[typing.List[typing.Union[Form, cpp.fem.Form]]], bcs: typing.List[DirichletBC] = [], diagonal: float = 1.0) -> PETSc.Mat: """Assemble bilinear forms into matrix""" _a = _create_cpp_form(a) V = _extract_function_spaces(_a) is_rows = cpp.la.create_petsc_index_sets([(Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[0]]) is_cols = cpp.la.create_petsc_index_sets([(Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[1]]) for i, a_row in enumerate(_a): for j, a_sub in enumerate(a_row): if a_sub is not None: Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j]) assemble_matrix(Asub, a_sub, bcs, diagonal) A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub) return A
def gather_PETScMatrix(A: PETSc.Mat, root=0) -> scipy.sparse.csr_matrix: """ Given a distributed PETSc matrix, gather in on process 'root' in a scipy CSR matrix """ ai, aj, av = A.getValuesCSR() aj_all = MPI.COMM_WORLD.gather(aj, root=root) # type: ignore av_all = MPI.COMM_WORLD.gather(av, root=root) # type: ignore ai_all = MPI.COMM_WORLD.gather(ai, root=root) # type: ignore if MPI.COMM_WORLD.rank == root: ai_cum = [0] for ai in ai_all: # type: ignore offsets = ai[1:] + ai_cum[-1] ai_cum.extend(offsets) return scipy.sparse.csr_matrix( (np.hstack(av_all), np.hstack(aj_all), ai_cum), shape=A.getSize()) # type: ignore
def _(A: PETSc.Mat, a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, coeffs=Coefficients(None, None)) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not finalised, i.e. ghost values are not accumulated. """ c = (coeffs[0] if coeffs[0] is not None else pack_constants(a), coeffs[1] if coeffs[1] is not None else pack_coefficients(a)) _cpp.fem.petsc.assemble_matrix(A, a, c[0], c[1], bcs) if a.function_spaces[0].id == a.function_spaces[1].id: A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH) A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH) _cpp.fem.petsc.insert_diagonal(A, a.function_spaces[0], bcs, diagonal) return A
def _(A: PETSc.Mat, a: typing.Union[Form, cpp.fem.Form], bcs=[], diagonal: float = 1.0) -> PETSc.Mat: """Assemble bilinear form into an exiting matrix. The matrix is zeroed before assembly. Rows and columns of the matrix with Dirichlet boundary conditions zeroed, and ``scalar`` is placed on the diagonal for entries with a Dirichlet boundary condition. The matrix finalised, i.e. ghost values accumulated across MPI processes. """ A.zeroEntries() a_cpp = _create_cpp_form(a) cpp.fem.assemble_matrix(A, a_cpp, bcs, diagonal) A.assemble() return A
def matrix_split(Aww, badset): goodset = [] nw = Aww.getSize()[0] for ki in range(nw): if ki not in badset: goodset.append(ki) goodset.sort() gtt = PETSc.IS() btt = PETSc.IS() gtt.createGeneral(goodset) btt.createGeneral(badset) A1 = Mat() A2 = Mat() Aww.createSubMatrix(gtt, gtt, A1) Aww.createSubMatrix(btt, btt, A2) eigfind.eigfind(A1) eigfind.eigfind(A2) return A1, A2
def _(A: PETSc.Mat, a: typing.List[typing.List[typing.Union[Form, cpp.fem.Form]]], bcs: typing.List[DirichletBC] = [], diagonal: float = 1.0) -> PETSc.Mat: """Assemble bilinear forms into matrix""" _a = _create_cpp_form(a) for i, a_row in enumerate(_a): for j, a_block in enumerate(a_row): if a_block is not None: Asub = A.getNestSubMatrix(i, j) assemble_matrix(Asub, a_block, bcs) return A
def assemble_matrix(form: _fem.FormMetaClass, constraint: Union[MultiPointConstraint, Sequence[MultiPointConstraint]], bcs: Sequence[_fem.DirichletBCMetaClass] = [], diagval: _PETSc.ScalarType = 1, A: _PETSc.Mat = None) -> _PETSc.Mat: """ Assemble a compiled DOLFINx bilinear form into a PETSc matrix with corresponding multi point constraints and Dirichlet boundary conditions. Parameters ---------- form The compiled bilinear variational form constraint The multi point constraint bcs Sequence of Dirichlet boundary conditions diagval Value to set on the diagonal of the matrix (Default 1) A PETSc matrix to assemble into (optional) Returns ------- _PETSc.Mat The assembled bi-linear form """ if not isinstance(constraint, Sequence): assert(form.function_spaces[0] == form.function_spaces[1]) constraint = (constraint, constraint) # Generate matrix with MPC sparsity pattern if A is None: A = cpp.mpc.create_matrix(form, constraint[0]._cpp_object, constraint[1]._cpp_object) A.zeroEntries() # Assemble matrix in C++ cpp.mpc.assemble_matrix(A, form, constraint[0]._cpp_object, constraint[1]._cpp_object, bcs, diagval) # Add one on diagonal for Dirichlet boundary conditions if form.function_spaces[0] is form.function_spaces[1]: A.assemblyBegin(_PETSc.Mat.AssemblyType.FLUSH) A.assemblyEnd(_PETSc.Mat.AssemblyType.FLUSH) _cpp.fem.petsc.insert_diagonal(A, form.function_spaces[0], bcs, diagval) A.assemble() return A
def petsc_to_local_CSR(A: PETSc.Mat, mpc: dolfinx_mpc.MultiPointConstraint): """ Convert a PETSc matrix to a local CSR matrix (scipy) including ghost entries """ global_indices = np.asarray( mpc.function_space.dofmap.index_map.global_indices(), dtype=PETSc.IntType) sort_index = np.argsort(global_indices) is_A = PETSc.IS().createGeneral(global_indices[sort_index]) A_loc = A.createSubMatrices(is_A)[0] ai, aj, av = A_loc.getValuesCSR() A_csr = scipy.sparse.csr_matrix((av, aj, ai)) return A_csr[global_indices[:, None], global_indices]
def assemble(self): """Ax=b Assembles A and b using the matrices and RHS and indices stored in the file self.fmatrices. self.A, self.b and self.x then contain initialized petsc matricx and vectors. """ l = Matrices(self.fmatrices) nn, ne, linear = l.loadsize() assert linear in [0, 1] if linear: dim = 4 else: dim = 10 self.nele = ne if self.verbose: pbar = MyBar("Global matrix and RHS: ") if self.verbose: pbar.init(ne - 1) IM = InsertMode.ADD_VALUES self.A = Mat() if linear: prealloc = 30 else: prealloc = 100 self.A.createSeqAIJ(nn, nz=prealloc) # self.A.create() # self.A.setSizes(nn) self.A.setFromOptions() # self.A.option = Mat.Option.ROWS_SORTED # self.A.option = Mat.Option.COLUMNS_SORTED # self.A.option = Mat.Option.STRUCTURALLY_SYMMETRIC self.x, self.b = self.A.getVecs() self.b.zeroEntries() for i in range(ne): indices = l.loadindices(dim) Ae = l.loadmatrix(dim) Fe = l.loadvector(dim) self.A.setValues(indices, indices, Ae, IM) self.b.setValues(indices, Fe, IM) if self.verbose: pbar.update(i) self.A.assemble()
def makecorrection(Ahlist, Bpet): nl = len(Ahlist) - 1 Acorlist = [None] * nl for k in range(nl): Ah = Ahlist[k] btt = Bpet[k] Abad = Mat() Ah.createSubMatrix(btt, btt, Abad) Abad.assemblyBegin() Abad.assemblyEnd() Acorlist[k] = Abad.copy() return Acorlist
def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, coeffs=Coefficients(None, None)) -> PETSc.Mat: """Assemble bilinear forms into matrix""" c = (coeffs[0] if coeffs[0] is not None else pack_constants(a), coeffs[1] if coeffs[1] is not None else pack_coefficients(a)) for i, (a_row, const_row, coeff_row) in enumerate(zip(a, c[0], c[1])): for j, (a_block, const, coeff) in enumerate(zip(a_row, const_row, coeff_row)): if a_block is not None: Asub = A.getNestSubMatrix(i, j) assemble_matrix(Asub, a_block, bcs, diagonal, (const, coeff)) return A
def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" constants = [[form and _pack_constants(form) for form in forms] for forms in a] if constants is None else constants coeffs = [[{} if form is None else _pack_coefficients(form) for form in forms] for forms in a] if coeffs is None else coeffs V = _extract_function_spaces(a) is_rows = _cpp.la.petsc.create_index_sets([ (Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[0] ]) is_cols = _cpp.la.petsc.create_index_sets([ (Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[1] ]) # Assemble form for i, a_row in enumerate(a): for j, a_sub in enumerate(a_row): if a_sub is not None: Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j]) _cpp.fem.petsc.assemble_matrix(Asub, a_sub, constants[i][j], coeffs[i][j], bcs, True) A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub) # Flush to enable switch from add to set in the matrix A.assemble(PETSc.Mat.AssemblyType.FLUSH) # Set diagonal for i, a_row in enumerate(a): for j, a_sub in enumerate(a_row): if a_sub is not None: Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j]) if a_sub.function_spaces[0] is a_sub.function_spaces[1]: _cpp.fem.petsc.insert_diagonal(Asub, a_sub.function_spaces[0], bcs, diagonal) A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub) return A
def build_Wuu(self): Bm = as_backend_type(self.B).mat() BT = Bm.transpose(Mat()) if self.point_variance: BtG_mat = BT.matMult(self.invG.mat()) BtGB_mat = BtG_mat.matMult(Bm) BtGB = Matrix(PETScMatrix(BtGB_mat)) Wuu = BtGB #* du self.BtG = Matrix(PETScMatrix(BtG_mat)) else: BtB_mat = BT.matMult(Bm) BtB = Matrix(PETScMatrix((1.0 / self.noise_variance) * BtB_mat)) Wuu = BtB self.BtG = Matrix(PETScMatrix((1.0 / self.noise_variance) * BT)) return Wuu
def makecorrection(Ahlist, poorlist): Acorlist = [None] * (len(Ahlist) - 1) for k in range(len(Ahlist) - 1): Ah = Ahlist[k] badpet = PETSc.IS() badpet.createGeneral(poorlist[k]) Abad = Mat() Ah.createSubMatrix(badpet, badpet, Abad) Abad.assemblyBegin() Abad.assemblyEnd() Acorlist[k] = Abad.copy() return Acorlist
def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" constants = [[form and _pack_constants(form) for form in forms] for forms in a] if constants is None else constants coeffs = [[{} if form is None else _pack_coefficients(form) for form in forms] for forms in a] if coeffs is None else coeffs for i, (a_row, const_row, coeff_row) in enumerate(zip(a, constants, coeffs)): for j, (a_block, const, coeff) in enumerate(zip(a_row, const_row, coeff_row)): if a_block is not None: Asub = A.getNestSubMatrix(i, j) assemble_matrix(Asub, a_block, bcs, diagonal, const, coeff) return A
def poisson(da: PETSc.DM, spacing=None, a=0.0, b=1.0, A: PETSc.Mat = None, bcs=None) -> PETSc.Mat: """ Return second order matrix for problem a I + b div grad Note ---- this implementation is pretty slow. Can it be speeded up with cython somehow """ if A is None: A = da.createMatrix() if spacing is None: spacing = [1.0] * da.dim if bcs is None: bcs = [0]*da.dim # use stencil to set entries row = PETSc.Mat.Stencil() col = PETSc.Mat.Stencil() if da.dim == 2: dx, dy = spacing hxy = dx/dy hyx = dy/dx ir = range(*da.ranges[0]) jr = range(*da.ranges[1]) dx, dy = spacing for i, j in product(ir, jr): row.index = (i,j) for index, value in [((i, j), a + b * (-2 * hyx - 2 *hxy)), ((i-1, j), b * hyx), ((i+1, j), b * hyx), ((i, j-1), b*hxy), ((i, j+1), b*hxy)]: col.index = index A.setValueStencil(row, col, value) A.assemblyBegin() A.assemblyEnd() return A
def assemble(self): """Ax=b Assembles A and b using the matrices and RHS and indices stored in the file self.fmatrices. self.A, self.b and self.x then contain initialized petsc matricx and vectors. """ l=Matrices(self.fmatrices) nn,ne,linear=l.loadsize() assert linear in [0,1] if linear: dim=4 else: dim=10 self.nele=ne if self.verbose: pbar=MyBar("Global matrix and RHS: ") if self.verbose: pbar.init(ne-1) IM=InsertMode.ADD_VALUES self.A=Mat() if linear: prealloc=30 else: prealloc=100 self.A.createSeqAIJ(nn,nz=prealloc) # self.A.create() # self.A.setSizes(nn) self.A.setFromOptions() # self.A.option = Mat.Option.ROWS_SORTED # self.A.option = Mat.Option.COLUMNS_SORTED # self.A.option = Mat.Option.STRUCTURALLY_SYMMETRIC self.x,self.b=self.A.getVecs() self.b.zeroEntries() for i in range(ne): indices=l.loadindices(dim) Ae=l.loadmatrix(dim) Fe=l.loadvector(dim) self.A.setValues(indices,indices,Ae,IM) self.b.setValues(indices,Fe,IM) if self.verbose: pbar.update(i) self.A.assemble()
puse = [] #first one #emax1=1.973297 #emax1=2.968916 #calc # B1=[3241, 3748, 3751, 3496, 3753, 3242, 3243, 3244, 3245, 3246, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3763, 3764, 3511, 3762, 3761, 3509, 3253, 3508, 3255, 3752, 3497, 3498, 3247, 3239, 3757, 3758, 3251, 3252, 3507, 3059, 3318, 3510, 3765] # B1.sort() # matrix_split.matrix_split(Ahere,B1) # quit() emax1 = 1.973094 ptt = pnone[0].copy() pnew = makenew(Ahere, ptt, emax1) puse.append(pnew) #second one A2 = Mat() Ahere.PtAP(pnew, A2) #eigfind.eigfind(A2) # B2 = [471, 408, 582, 583, 584, 585, 631, 455, 431, 498, 434, 500, 469, 470, 501, 499, 474, 539, 540, 541] # B2.sort() # matrix_split.matrix_split(A2,B2) # quit() ptt2 = pnone[1].copy() #emax2=1.505117 #emax2=1.559350 # clac emax2 = 1.504936 pnew2 = makenew(A2, ptt2, emax2) puse.append(pnew2) #third one
L = f * v * dx + g * v * ds A = PETScMatrix() b = PETScVector() assemble_system(a, L, bc, A_tensor=A, b_tensor=b) A = A.mat() b = b.vec() # ========================================================================= # Construct the alist for systems on levels from fine to coarse # construct the transfer operators first ruse = [None] * (nl - 1) Alist = [None] * (nl) ruse[0] = Mat() puse[0].transpose(ruse[0]) Alist[0] = A for il in range(1, nl-1): ruse[il] = Mat() puse[il].transpose(ruse[il]) Alist[il] = Mat() Alist[il - 1].PtAP(puse[il - 1], Alist[il]) # find the coarsest grid matrix Alist[nl-1] = Mat() Alist[nl-2].PtAP(puse[nl-2], Alist[nl-1]) # ========================================================= # Set initial guess
def J(self, x: PETSc.Vec, A: PETSc.Mat): A.zeroEntries() dolfinx_mpc.assemble_matrix(self._a, self.mpc, bcs=self.bcs, A=A) A.assemble()
mat = pc.getMGInterpolation(ih) prouse.append(mat.copy()) print(mat.size) pc.destroy() ksp.destroy() del ksp return nlevel, prouse nl, prolongation = makepro(A, b) restriction = [None] * (nl - 1) Alist = [None] * nl restriction[0] = Mat() prolongation[0].transpose(restriction[0]) Alist[0] = Apt for i_level in range(1, nl - 1): restriction[i_level] = Mat() prolongation[i_level].transpose(restriction[i_level]) Alist[i_level] = Mat() Alist[i_level - 1].PtAP(prolongation[i_level - 1], Alist[i_level]) Bfinemore = [ 23041, 23042, 514, 31238, 31239, 31240, 31241, 41482, 31243, 36876, 36877, 41484, 36879, 41485, 38434, 38435, 38436, 38437, 557, 26161, 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 36930, 36931, 36933, 36934, 36935, 36424, 36425, 36426, 36427, 36936, 36428, 36423, 36429, 36938, 593, 594, 595, 592, 596, 598, 599, 597, 600, 36443, 36444, 603, 1119, 1120, 610,
class System: def __init__(self,fmesh,fmatrices,fboundaries,verbose=True): self.fmesh=fmesh self.fmatrices=fmatrices self.fboundaries=fboundaries self.verbose=verbose def compute_element_matrices(self,bvalues,lam): """Calculates the element matrices and RHS and includes boundary conditions in them. The matrices and RHS together with global indices and are stored in self.fmatrices file. bvalues is a dict with boundary number and a double value example: bvalues={1:1.0, 2: 0.0} lam: double array of lambda for each element """ if self.verbose: up=MyBar("Element matrices and RHS: ") else: up=None libmeshpy.mesh(self.fmesh,self.fmatrices,self.fboundaries, bvalues.values(),bvalues.keys(),lam,up) def assemble(self): """Ax=b Assembles A and b using the matrices and RHS and indices stored in the file self.fmatrices. self.A, self.b and self.x then contain initialized petsc matricx and vectors. """ l=Matrices(self.fmatrices) nn,ne,linear=l.loadsize() assert linear in [0,1] if linear: dim=4 else: dim=10 self.nele=ne if self.verbose: pbar=MyBar("Global matrix and RHS: ") if self.verbose: pbar.init(ne-1) IM=InsertMode.ADD_VALUES self.A=Mat() if linear: prealloc=30 else: prealloc=100 self.A.createSeqAIJ(nn,nz=prealloc) # self.A.create() # self.A.setSizes(nn) self.A.setFromOptions() # self.A.option = Mat.Option.ROWS_SORTED # self.A.option = Mat.Option.COLUMNS_SORTED # self.A.option = Mat.Option.STRUCTURALLY_SYMMETRIC self.x,self.b=self.A.getVecs() self.b.zeroEntries() for i in range(ne): indices=l.loadindices(dim) Ae=l.loadmatrix(dim) Fe=l.loadvector(dim) self.A.setValues(indices,indices,Ae,IM) self.b.setValues(indices,Fe,IM) if self.verbose: pbar.update(i) self.A.assemble() def solve(self,iterguess=23): """Solves the system Ax=b. A is stored in self.A b is stored in self.b x is stored in self.x all three of them must be initialized petsc vectors (and a matrix) and the solution will be stored in self.x as a numpy array. The self.x is also returned from "solve", so that the user doesn't have to know about self.x. The iterguess is the guess for the number of iterations the solver is going to make. This is used in the progress bar. If it is overestimated, the progressbar will jump for example from 60% to 100% at the end, if it is underestimated, the progressbar will stop at 99% (exactly at (iterguess-1)/iterguess * 100) but the solver will be still computing and the progressbar will be updated to 100% only when it returns.""" if self.verbose: pbar=MyBar("Solving Ax=b: ") if self.verbose: pbar.init(iterguess) def upd(ksp,iter,rnorm): #print "iter:",iter,"norm:",rnorm if iter < iterguess: pbar.update(iter) ksp = KSP() ksp.create() ksp.setOperators(self.A,self.A,Mat.Structure.SAME_NONZERO_PATTERN) ksp.setFromOptions() if self.verbose: ksp.setMonitor(upd) ksp.solve(self.b,self.x) self.x=self.x.getArray() if self.verbose: pbar.update(iterguess) return self.x def gradient(self,x): """Computes a gradient of the scalar field defined on every node (numpy array x). The gradient is computed on every element and the result is returned as a list of 3 numpy arrays (x,y,z) components.""" gx = numpy.zeros(self.nele,'d') gy = numpy.zeros(self.nele,'d') gz = numpy.zeros(self.nele,'d') if self.verbose: up=MyBar("Gradient: ") else: up=None libmeshpy.grad(self.fmesh,x,gx,gy,gz,up) return gx,gy,gz def integ(self, grad, boundarynum): """Integrates the normal component of "grad" (list of 3 numpy arrays of floats for each element) over the boundary given by "boundarynum". We are integrating grad*n, where n is the normal, pointing always out of the element. boundarynum defines a set of elements and their faces, over which we are integrating and this defines the normal definitely. Returns a float (=the value of the surface integral).""" x,y,z=grad if self.verbose: up=MyBar("Integrating over surface %d: "%(boundarynum)) else: up=None return libmeshpy.integ(self.fmesh,self.fboundaries,x,y,z,boundarynum,up) def save(self, fsol, x, g): "Saves x and g to a file fsol" import tables h5=tables.openFile(fsol,mode="w",title="Test") gsol=h5.createGroup(h5.root,"solver","Ax=b") h5.createArray(gsol,"x",x,"solution vector") h5.createArray(gsol,"grad",g,"gradient of the solution vector") h5.close() def load(self, fname): "Loads x and g from the file fname and returns (x,g)" import tables h5=tables.openFile(fname,mode="r") x=h5.root.solver.x.read() g=h5.root.solver.grad.read() h5.close() return (x,g)
class System: def __init__(self, fmesh, fmatrices, fboundaries, verbose=True): self.fmesh = fmesh self.fmatrices = fmatrices self.fboundaries = fboundaries self.verbose = verbose def compute_element_matrices(self, bvalues, lam): """Calculates the element matrices and RHS and includes boundary conditions in them. The matrices and RHS together with global indices and are stored in self.fmatrices file. bvalues is a dict with boundary number and a double value example: bvalues={1:1.0, 2: 0.0} lam: double array of lambda for each element """ if self.verbose: up = MyBar("Element matrices and RHS: ") else: up = None libmeshpy.mesh(self.fmesh, self.fmatrices, self.fboundaries, bvalues.values(), bvalues.keys(), lam, up) def assemble(self): """Ax=b Assembles A and b using the matrices and RHS and indices stored in the file self.fmatrices. self.A, self.b and self.x then contain initialized petsc matricx and vectors. """ l = Matrices(self.fmatrices) nn, ne, linear = l.loadsize() assert linear in [0, 1] if linear: dim = 4 else: dim = 10 self.nele = ne if self.verbose: pbar = MyBar("Global matrix and RHS: ") if self.verbose: pbar.init(ne - 1) IM = InsertMode.ADD_VALUES self.A = Mat() if linear: prealloc = 30 else: prealloc = 100 self.A.createSeqAIJ(nn, nz=prealloc) # self.A.create() # self.A.setSizes(nn) self.A.setFromOptions() # self.A.option = Mat.Option.ROWS_SORTED # self.A.option = Mat.Option.COLUMNS_SORTED # self.A.option = Mat.Option.STRUCTURALLY_SYMMETRIC self.x, self.b = self.A.getVecs() self.b.zeroEntries() for i in range(ne): indices = l.loadindices(dim) Ae = l.loadmatrix(dim) Fe = l.loadvector(dim) self.A.setValues(indices, indices, Ae, IM) self.b.setValues(indices, Fe, IM) if self.verbose: pbar.update(i) self.A.assemble() def solve(self, iterguess=23): """Solves the system Ax=b. A is stored in self.A b is stored in self.b x is stored in self.x all three of them must be initialized petsc vectors (and a matrix) and the solution will be stored in self.x as a numpy array. The self.x is also returned from "solve", so that the user doesn't have to know about self.x. The iterguess is the guess for the number of iterations the solver is going to make. This is used in the progress bar. If it is overestimated, the progressbar will jump for example from 60% to 100% at the end, if it is underestimated, the progressbar will stop at 99% (exactly at (iterguess-1)/iterguess * 100) but the solver will be still computing and the progressbar will be updated to 100% only when it returns.""" if self.verbose: pbar = MyBar("Solving Ax=b: ") if self.verbose: pbar.init(iterguess) def upd(ksp, iter, rnorm): #print "iter:",iter,"norm:",rnorm if iter < iterguess: pbar.update(iter) ksp = KSP() ksp.create() ksp.setOperators(self.A, self.A, Mat.Structure.SAME_NONZERO_PATTERN) ksp.setFromOptions() if self.verbose: ksp.setMonitor(upd) ksp.solve(self.b, self.x) self.x = self.x.getArray() if self.verbose: pbar.update(iterguess) return self.x def gradient(self, x): """Computes a gradient of the scalar field defined on every node (numpy array x). The gradient is computed on every element and the result is returned as a list of 3 numpy arrays (x,y,z) components.""" gx = numpy.zeros(self.nele, 'd') gy = numpy.zeros(self.nele, 'd') gz = numpy.zeros(self.nele, 'd') if self.verbose: up = MyBar("Gradient: ") else: up = None libmeshpy.grad(self.fmesh, x, gx, gy, gz, up) return gx, gy, gz def integ(self, grad, boundarynum): """Integrates the normal component of "grad" (list of 3 numpy arrays of floats for each element) over the boundary given by "boundarynum". We are integrating grad*n, where n is the normal, pointing always out of the element. boundarynum defines a set of elements and their faces, over which we are integrating and this defines the normal definitely. Returns a float (=the value of the surface integral).""" x, y, z = grad if self.verbose: up = MyBar("Integrating over surface %d: " % (boundarynum)) else: up = None return libmeshpy.integ(self.fmesh, self.fboundaries, x, y, z, boundarynum, up) def save(self, fsol, x, g): "Saves x and g to a file fsol" import tables h5 = tables.openFile(fsol, mode="w", title="Test") gsol = h5.createGroup(h5.root, "solver", "Ax=b") h5.createArray(gsol, "x", x, "solution vector") h5.createArray(gsol, "grad", g, "gradient of the solution vector") h5.close() def load(self, fname): "Loads x and g from the file fname and returns (x,g)" import tables h5 = tables.openFile(fname, mode="r") x = h5.root.solver.x.read() g = h5.root.solver.grad.read() h5.close() return (x, g)
def mg(Ah, bh, uh, prolongation, N_cycles, N_levels, ksptype, pctype): '''multigrid for N level mesh Ah is the matrix, bh is rhs on the finest grid, uh is the initial guess for finest grid prolongation is a list containing all of operators from fine-to-coarse N_cycles is number of cycles and N_levels is number of levels''' r0 = residual(Ah, bh, uh) # make a restriction list and gird operator list and rhs list # and initial guess list # initialize the first entity restriction = [None] * (N_levels - 1) Alist = [None] * N_levels blist = [None] * N_levels restriction[0] = Mat() prolongation[0].transpose(restriction[0]) uhlist = [None] * N_levels Alist[0] = Ah blist[0] = bh uhlist[0] = uh # calculate the restriction, matrix, and initial guess lists # except coarsest grid, since transfer operator and initial guess # is not defined on that level for i_level in range(1, N_levels - 1): restriction[i_level] = Mat() prolongation[i_level].transpose(restriction[i_level]) Alist[i_level] = Mat() Alist[i_level - 1].PtAP(prolongation[i_level - 1], Alist[i_level]) uhlist[i_level] = restriction[i_level - 1] * uhlist[i_level - 1] # find the coarsest grid matrix Alist[N_levels - 1] = Mat() Alist[N_levels - 2].PtAP(prolongation[N_levels - 2], Alist[N_levels - 1]) for num_cycle in range(N_cycles): # restriction to coarse grids for i in range(N_levels - 1): # apply smoother to every level except the coarsest level local_correction(Alist[i], blist[i], uhlist[i], Blist[i]) smoother(Alist[i], blist[i], 1, uhlist[i], ksptype, pctype) local_correction(Alist[i], blist[i], uhlist[i], Blist[i]) smoother(Alist[i], blist[i], 1, uhlist[i], ksptype, pctype) local_correction(Alist[i], blist[i], uhlist[i], Blist[i]) # obtain the rhs for next level res = blist[i] - Alist[i] * uhlist[i] blist[i + 1] = restriction[i] * res # on the coarsest grid, apply direct lu uhlist[N_levels - 1] = direct(Alist[N_levels - 1], blist[N_levels - 1]) # prolongation back to fine grids for j in range(N_levels - 2, -1, -1): uhlist[j] += prolongation[j] * uhlist[j + 1] local_correction(Alist[j], blist[j], uhlist[j], Blist[j]) smoother(Alist[j], blist[j], 1, uhlist[j], ksptype, pctype) local_correction(Alist[j], blist[j], uhlist[j], Blist[j]) smoother(Alist[j], blist[j], 1, uhlist[j], ksptype, pctype) local_correction(Alist[j], blist[j], uhlist[j], Blist[j]) # calculate the relative residual res4 = residual(Ah, bh, uhlist[0]) / r0 #print('relative residual after', num_cycle + 1, 'cycles is:', res4) print(res4) return uhlist[0]
ksp.destroy() del ksp return nlevel, prouse # find the number of levels and prolongation list of AMG nl, puse = makepro(A, b) #eigfind.eigfind(Apt) #quit() #================================================================================ ruse = [None] * (nl - 1) Ause = [None] * nl ruse[0] = Mat() puse[0].transpose(ruse[0]) Ause[0] = Apt for il in range(1, nl - 1): ruse[il] = Mat() puse[il].transpose(ruse[il]) Ause[il] = Mat() Ause[il - 1].PtAP(puse[il - 1], Ause[il]) # find the coarsest grid matrix Ause[nl - 1] = Mat() Ause[nl - 2].PtAP(puse[nl - 2], Ause[nl - 1]) #============================================================================
U = np.loadtxt('SVD_basis') U = U[:,0:DB] U_transpose = U.conj().T #load mass matrix and reduce it rp = np.loadtxt('iam',int) rp = rp.astype(petsc4py.PETSc.IntType) ci = np.loadtxt('jam',int) ci = ci.astype(petsc4py.PETSc.IntType) nz = np.loadtxt('am') nr = rp.shape[0] - 1 nc = nr M = Mat().createAIJ(size=(nr,nc),csr=(rp,ci,nz)) M_intermediate = np.zeros((nr,DB),'d') for i in range(0,nr): res = M.getRow(i) M_intermediate[i,:] = np.dot(res[1],U[res[0],:]) M_pod = np.dot(U_transpose, M_intermediate) np.savetxt('M_pod', M_pod, delimiter=' ') #load stiffness matrix and reduce it rp = np.loadtxt('ias',int) rp = rp.astype(petsc4py.PETSc.IntType) ci = np.loadtxt('jas',int)