def solve(t_y, t_x, mask, t_y_weights=None, t_x_weights=None): """Solve for the image which best matches the target vertical gradients t_y and horizontal gradients t_x, e.g. the one which minimizes sum of squares of the residual sum of (I[i,j] - I[i-1,j] - t_y[i,j])**2 + (I[i,j] - I[i,j-1] - t_x[i,j])**2 Only considers the target gradients lying entirely within the mask. The first row of t_y and the first column of t_x are ignored. Optionally, you may pass in an array with the weights corresponding to each target gradient. The solution is unique up to a constant added to each of the pixels. """ if t_y_weights is None: t_y_weights = np.ones(t_y.shape) if t_x_weights is None: t_x_weights = np.ones(t_x.shape) M, N = mask.shape numbers = get_numbers(mask) A = get_A(mask, t_y_weights, t_x_weights) b = get_b(t_y, t_x, mask, t_y_weights, t_x_weights) solver = pyamg.ruge_stuben_solver(A) x = solver.solve(b) I = np.zeros(mask.shape) for i in range(M): for j in range(N): I[i,j] = x[numbers[i,j]] return I
def test(): class Gamma0(Subdomain): def is_inside(self, x): return x[1] < 0.5 is_boundary_only = True class Gamma1(Subdomain): def is_inside(self, x): return x[1] >= 0.5 is_boundary_only = True class Poisson(object): def apply(self, u): return integrate(lambda x: -n_dot_grad(u(x)), dS) - integrate( lambda x: 50 * sin(2 * pi * x[0]), dV ) def dirichlet(self, u): return [(lambda x: u(x) - 0.0, Gamma0()), (lambda x: u(x) - 1.0, Gamma1())] # # Read the mesh from file # mesh, _, _ = pyfvm.reader.read('circle.vtu') # Create mesh using meshzoo import meshzoo vertices, cells = meshzoo.cube(0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 30, 30, 30) mesh = meshplex.MeshTetra(vertices, cells) # vertices, cells = meshzoo.rectangle(0.0, 2.0, 0.0, 1.0, 401, 201) # mesh = meshplex.MeshTri(vertices, cells) print(len(vertices)) # import mshr # import dolfin # # h = 2.5e-3 # h = 1.e-1 # # cell_size = 2 * pi / num_boundary_points # c = mshr.Circle(dolfin.Point(0., 0., 0.), 1, int(2*pi / h)) # # cell_size = 2 * bounding_box_radius / res # m = mshr.generate_mesh(c, 2.0 / h) # coords = m.coordinates() # coords = numpy.c_[coords, numpy.zeros(len(coords))] # cells = m.cells().copy() # mesh = meshplex.MeshTri(coords, cells) # # mesh = meshplex.lloyd_smoothing(mesh, 1.0e-4) matrix, rhs = pyfvm.discretize_linear(Poisson(), mesh) # ml = pyamg.smoothed_aggregation_solver(matrix) ml = pyamg.ruge_stuben_solver(matrix) u = ml.solve(rhs, tol=1e-10) # from scipy.sparse import linalg # u = linalg.spsolve(matrix, rhs) mesh.write("out.vtk", point_data={"u": u}) return
def test_laplacian(): import pylab as pl # Setup grid nx, ny = 500, 500 d = 2*pi/nx Lx, Ly = nx * d, ny * d g = 0 # make grid x = np.arange(-g, nx+g)*d y = np.arange(-g, ny+g)*d dx = x[1]-x[0] dy = y[1]-y[0] x, y = np.meshgrid(x, y, indexing='ij') # build laplacian A = build_laplacian_matrix(nx,ny,d=d) # A = poisson((nx, ny), spacing=(dx, dy), format='csr')/d/d # right hand side f = np.sin(x)*np.cos(2*y) f = np.random.rand(A.shape[0]) p_ex = np.sin(x)*np.cos(2*y)/(-1 - 4) print("Timing information") print("==================") print("") # with elapsed_timer() as elapsed: # p_ap = la.spsolve(A, f.ravel()) # print("spsolve {0}".format(elapsed())) with elapsed_timer() as elapsed: p_cg = la.cg(A, f.ravel())[0] print("cg {0}".format(elapsed())) # with elapsed_timer() as elapsed: # p_ap = la.gmres(A, f.ravel()) # print("gmres {0}".format(elapsed())) ml = ruge_stuben_solver(A) M = ml.aspreconditioner() with elapsed_timer() as elapsed: p_amg = la.cg(A, f.ravel(),M=M) print("pyamg cg {0}".format(elapsed())) pl.show()
def _solve_cg_mg(lap_sparse, B, tol): if not amg_loaded: print """the pyamg module (http://code.google.com/p/pyamg/) must be installed to use the amg mode""" raise ImportError X = [] #lap_sparse = lap_sparse.tocsr() ml = ruge_stuben_solver(lap_sparse) M = ml.aspreconditioner(cycle='V') for i in range(len(B)): x0 = cg(lap_sparse, -B[i].todense(), tol=tol, M=M, maxiter=30)[0] X.append(x0) X = np.array(X) X = np.argmax(X, axis=0) return X
def _solve_cg_mg(lap_sparse, B, tol): """ solves lap_sparse X_i = B_i for each phase i, using the conjugate gradient method with a multigrid preconditioner (ruge-stuben from pyamg). For each pixel, the label i corresponding to the maximal X_i is returned. """ X = [] ml = ruge_stuben_solver(lap_sparse) M = ml.aspreconditioner(cycle='V') for i in range(len(B)): x0 = cg(lap_sparse, -B[i].todense(), tol=tol, M=M, maxiter=30)[0] X.append(x0) X = np.array(X) X = np.argmax(X, axis=0) return X
def _solve_cg_mg(lap_sparse, B, tol, return_full_prob=False): """ solves lap_sparse X_i = B_i for each phase i, using the conjugate gradient method with a multigrid preconditioner (ruge-stuben from pyamg). For each pixel, the label i corresponding to the maximal X_i is returned. """ X = [] ml = ruge_stuben_solver(lap_sparse) M = ml.aspreconditioner(cycle='V') for i in range(len(B)): x0 = cg(lap_sparse, -B[i].todense(), tol=tol, M=M, maxiter=30)[0] X.append(x0) if not return_full_prob: X = np.array(X) X = np.argmax(X, axis=0) return X
def solver(A, b, **solve_time_kwargs): kwargs.update(solve_time_kwargs) import pyamg ml = pyamg.ruge_stuben_solver(A) kwargs['M'] = ml.aspreconditioner() # params to be developed try: sol, info, _ = krylov(A, b, **{'callback': callback, **kwargs}) except: sol, info = krylov(A, b, **{'callback': callback, **kwargs}) if info > 0: warnings.warn("Convergence not achieved!") elif info == 0 and verbose: print(f"{krylov.__name__} converged to " + f"tol={kwargs.get('tol', 'default')} and " + f"atol={kwargs.get('atol', 'default')}") return sol
def solver(A, b): num_iters = 0 def callback(xk): nonlocal num_iters num_iters += 1 ml = pyamg.ruge_stuben_solver(A) ptmp = ml.solve(b, tol=1e-16, callback=callback) # ptmp = scipy.sparse.linalg.spsolve(A,b,callback=callback) atol = 1e-5 tol = 1e-12 # ptmp,_ = scipy.sparse.linalg.cg(A, b,p0[1:-1, 1:-1].ravel(),callback=callback,tol=tol) # if max(tol*np.linalg.norm(b,2),atol) == atol: # print('atol') # else: # print('tol') return ptmp, num_iters
def precondieitoner(self): tspace = self.tensorspace vspace = self.vectorspace tgdof = tspace.number_of_global_dofs() gdim = tspace.geo_dimension() bcs, ws = self.integrator.quadpts, self.integrator.weights phi = tspace.basis(bcs) # construct diag matrix D if gdim == 2: d = np.array([1, 1, 2]) elif gdim == 3: d = np.array([1, 1, 1, 2, 2, 2]) D = np.einsum('i, ijkm, m, ijkm, j->jk', ws, phi, d, phi, self.measure) tcell2dof = tspace.cell_to_dof() self.D = np.bincount(tcell2dof.flat, weights=D.flat, minlength=tgdof) # construct amg solver A = stiff_matrix(self.cspace, self.integrator, self.measure) isBdDof = self.cspace.boundary_dof() bdIdx = np.zeros((A.shape[0], ), np.int) bdIdx[isBdDof] = 1 Tbd = spdiags(bdIdx, 0, A.shape[0], A.shape[0]) T = spdiags(1-bdIdx, 0, A.shape[0], A.shape[0]) A = T@A@T + Tbd self.ml = pyamg.ruge_stuben_solver(A) # 这里要求必须有网格内部节点 # Get interpolation matrix NC = self.mesh.number_of_cells() bc = self.vectorspace.dof.multiIndex/self.vectorspace.p val = np.tile(bc, (NC, 1)) c2d0 = self.vectorspace.dof.cell2dof c2d1 = self.cspace.cell_to_dof() gdim = self.tensorspace.geo_dimension() I = np.einsum('ij, k->ijk', c2d0, np.ones(gdim+1)) J = np.einsum('ik, j->ijk', c2d1, np.ones(len(bc))) cgdof = self.cspace.number_of_global_dofs() fgdof = self.vectorspace.number_of_global_dofs()/self.mesh.geo_dimension() self.PI = csr_matrix((val.flat, (I.flat, J.flat)), shape=(fgdof, cgdof))
def get_new_points(mesh, tol=1.0e-10): cells = mesh.cells["nodes"].T row_idx = [] col_idx = [] val = [] a = numpy.ones(cells.shape[1], dtype=float) for i in [[0, 1], [1, 2], [2, 0]]: edges = cells[i] row_idx += [edges[0], edges[1], edges[0], edges[1]] col_idx += [edges[0], edges[1], edges[1], edges[0]] val += [+a, +a, -a, -a] row_idx = numpy.concatenate(row_idx) col_idx = numpy.concatenate(col_idx) val = numpy.concatenate(val) n = mesh.node_coords.shape[0] # Create CSR matrix for efficiency matrix = scipy.sparse.coo_matrix((val, (row_idx, col_idx)), shape=(n, n)) matrix = matrix.tocsr() # Apply Dirichlet conditions. verts = numpy.where(mesh.is_boundary_node)[0] # Set all Dirichlet rows to 0. for i in verts: matrix.data[matrix.indptr[i] : matrix.indptr[i + 1]] = 0.0 # Set the diagonal and RHS. d = matrix.diagonal() d[mesh.is_boundary_node] = 1.0 matrix.setdiag(d) rhs = numpy.zeros((n, 2)) rhs[mesh.is_boundary_node] = mesh.node_coords[mesh.is_boundary_node] # out = scipy.sparse.linalg.spsolve(matrix, rhs) ml = pyamg.ruge_stuben_solver(matrix) # Keep an eye on multiple rhs-solves in pyamg, # <https://github.com/pyamg/pyamg/issues/215>. out = numpy.column_stack( [ml.solve(rhs[:, 0], tol=tol), ml.solve(rhs[:, 1], tol=tol)] ) return out[mesh.is_interior_node]
def _solve_linear_system(lap_sparse, B, tol, mode): if mode is None: mode = 'cg_j' if mode == 'cg_mg' and not amg_loaded: warn( '"cg_mg" not available, it requires pyamg to be installed. ' 'The "cg_j" mode will be used instead.', stacklevel=2) mode = 'cg_j' if mode == 'bf': X = spsolve(lap_sparse, B.toarray()).T else: maxiter = None if mode == 'cg': if UmfpackContext is None: warn( '"cg" mode may be slow because UMFPACK is not available. ' 'Consider building Scipy with UMFPACK or use a ' 'preconditioned version of CG ("cg_j" or "cg_mg" modes).', stacklevel=2) M = None elif mode == 'cg_j': M = sparse.diags(1.0 / lap_sparse.diagonal()) else: # mode == 'cg_mg' lap_sparse = lap_sparse.tocsr() ml = ruge_stuben_solver(lap_sparse) M = ml.aspreconditioner(cycle='V') maxiter = 30 cg_out = [ cg(lap_sparse, B[:, i].toarray(), tol=tol, M=M, maxiter=maxiter) for i in range(B.shape[1]) ] if np.any([info > 0 for _, info in cg_out]): warn( "Conjugate gradient convergence to tolerance not achieved. " "Consider decreasing beta to improve system conditionning.", stacklevel=2) X = np.asarray([x for x, _ in cg_out]) return X
def picard(A, M, u0, tol=1e-12, atol=1e-12, ml=None): if ml is None: ml = pyamg.ruge_stuben_solver(A) d0 = (u0 @ A @ u0) / (u0 @ M @ u0) while True: u1 = ml.solve(d0 * M @ u0, x0=u0, tol=1e-12, accel='cg').reshape(-1) L0 = u1 @ M @ u1 L1 = u1 @ A @ u1 d1 = L1 / L0 if norm(u1 - u0, ord=1) / norm(u1, ord=1) < tol or np.abs(d1 - d0) < atol: u0 = u1 / np.max(np.abs(u1)) d0 = d1 break else: u0 = u1 / np.max(np.abs(u1)) d0 = d1 return u0, d0
def test(n=100): omega = 1.0 iterations = 1 print("Creating A") A = pyamg.gallery.poisson( (n, n), format='csr') # 2D Poisson problem on nxn grid print("Creating ref") ml = pyamg.ruge_stuben_solver(A, max_coarse=1, max_levels=100, presmoother=('jacobi', { "withrho": True, "omega": omega }), postsmoother=('jacobi', { "withrho": True, "omega": omega })) # construct the multigrid hierarchy mg = MultiGrid(A, omega=omega, iterations=iterations) b = np.random.rand(A.shape[0]) # pick a random right hand side x0 = np.random.rand(A.shape[0]) xP = x0.copy() xV = x0.copy() xVa = x0.copy() xVa2 = x0.copy() xW = x0.copy() i = 0 print("residuals : ", n, i, np.linalg.norm(b - A * xP), np.linalg.norm(b - A * xV), np.linalg.norm(b - A * xW)) while True: i = i + 1 xP = ml.solve(b, tol=1e-9, maxiter=iterations, x0=xP) mg.vcycle(xV, b) mg.vcycle_alt(xVa, b) mg.vcycle_alt2(xVa2, b) mg.wcycle(xW, b) print("residuals: ", n, i, np.linalg.norm(b - A * xP), np.linalg.norm(b - A * xV), np.linalg.norm(b - A * xVa), np.linalg.norm(b - A * xVa2), np.linalg.norm(b - A * xW)) if np.linalg.norm(b - A * xV) < 1e-3: break
def solve1(a, L, uh, dirichlet=None, neuman=None, solver='cg'): space = a.space start = timer() A = a.get_matrix() b = L.get_vector() end = timer() print("Construct linear system time:", end - start) if neuman is not None: b += neuman.get_vector() if dirichlet is not None: AD, b = dirichlet.apply(A, b) else: AD = A # print("The condtion number is: ", np.linalg.cond(AD.todense())) if solver is 'cg': start = timer() D = AD.diagonal() M = spdiags(1 / D, 0, AD.shape[0], AD.shape[1]) uh[:], info = cg(AD, b, tol=1e-14, M=M) end = timer() print(info) elif solver is 'amg': start = timer() ml = pyamg.ruge_stuben_solver(AD) uh[:] = ml.solve(b, tol=1e-12, accel='cg').reshape((-1, )) end = timer() print(ml) elif solver is 'direct': start = timer() uh[:] = spsolve(AD, b) end = timer() else: print("We don't support solver: " + solver) print("Solve time:", end - start) return A
def __init__(self, A, P, isBdDof): """ Notes ----- 这里的边界条件处理放到矩阵和向量的乘积运算当中, 所心不需要修改矩阵本身 """ self.gdof = P.shape[0] self.GD = A.shape[0] // self.gdof self.A = A self.isBdDof = isBdDof # 处理预条件子的边界条件 bdIdx = np.zeros(P.shape[0], dtype=np.int_) bdIdx[isBdDof] = 1 Tbd = spdiags(bdIdx, 0, P.shape[0], P.shape[0]) T = spdiags(1 - bdIdx, 0, P.shape[0], P.shape[0]) P = T @ P @ T + Tbd self.ml = pyamg.ruge_stuben_solver(P)
def __init__(self, pde, n, tau, q): self.pde = pde self.mesh = pde.space_mesh(n) self.timemesh, self.tau = self.pde.time_mesh(tau) self.femspace = LagrangeFiniteElementSpace(self.mesh, 1) self.uh0 = self.femspace.interpolation(pde.initdata) self.uh1 = self.femspace.function() self.area = self.mesh.entity_measure('cell') self.integrator = self.mesh.integrator(q) self.integralalg = IntegralAlg(self.integrator, self.mesh, self.area) self.A, self.B, self.gradphi = grad_recovery_matrix(self.femspace) self.M = doperator.mass_matrix(self.femspace, self.integrator, self.area) self.K = self.get_stiff_matrix() self.D = self.M + self.tau * self.K self.ml = pyamg.ruge_stuben_solver(self.D) print(self.ml) self.current = 0
def mode_solver_initialisation(mode, solver_data, a, solver_tol): solver_data['solver_timing'], solver_data['solver_tol'] = [], solver_tol solver_data['is_solver_direct'] = [] id_n = sp.eye(a.shape[0], format='csr') solver_data['a'] = a solver_data['id_n'] = id_n if mode == 'pyamg': amg_hierarchy = pyamg.ruge_stuben_solver(a) orig_hierarchy = copy_hierarchy(amg_hierarchy) solver_data['amg_hierarchy'], solver_data['orig_hierarchy'] = amg_hierarchy, orig_hierarchy elif mode == 'pyamgE': B = np.ones((a.shape[0],1), dtype=a.dtype); amg_hierarchy = pyamg.rootnode_solver(a, max_levels = 15, max_coarse = 300, coarse_solver = 'pinv', presmoother = ('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother = ('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), BH = B.copy(), strength = ('evolution', {'epsilon': 4.0, 'k': 2, 'proj_type': 'l2'}), aggregate ='standard', smooth = ('energy', {'weighting': 'local', 'krylov': 'gmres', 'degree': 1, 'maxiter': 2}), improve_candidates = [('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), None, None, None, None, None, None, None, None, None, None, None, None, None, None]) orig_hierarchy = copy_hierarchy(amg_hierarchy) solver_data['amg_hierarchy'], solver_data['orig_hierarchy'] = amg_hierarchy, orig_hierarchy elif mode == 'splu': solver_data['lu'] = sla.splu(a.tocsc()) return
def __init__(self, A, F, P, I, isBdDof): """ Notes ----- 求解高次拉格朗日有限元的快速算法 """ self.gdof = len(isBdDof) self.A = A # 矩阵 (gdof, gdof), 注意这里是没有处理 D 氏边界的矩阵 self.F = F # 右端 (gdof, ), 注意这里也没有处理 D 氏边界 self.I = I # 插值矩阵 (gdof, NN), 把线性元的解插值到 p 次解 self.isBdDof = isBdDof # 获得磨光子 gdof = self.gdof bdIdx = np.zeros(gdof, dtype=np.int_) bdIdx[isBdDof] = 1 # 这里假定 A 的前 NN 个自由度是网格节点 Tbd = spdiags(bdIdx, 0, gdof, gdof) T = spdiags(1-bdIdx, 0, gdof, gdof) A = T@A@T + Tbd self.L0 = tril(A).tocsr() self.U0 = triu(A, k=1).tocsr() self.U1 = self.L0.T.tocsr() self.L1 = self.U0.T.tocsr() # 处理预条件子的边界条件 NN = P.shape[0] bdIdx = np.zeros(NN, dtype=np.int_) bdIdx[isBdDof[:NN]] = 1 # 这里假定 A 的前 NN 个自由度是网格节点 Tbd = spdiags(bdIdx, 0, NN, NN) T = spdiags(1-bdIdx, 0, NN, NN) P = T@P@T + Tbd self.ml = pyamg.ruge_stuben_solver(P) # P 的 D 氏边界条件用户先处理一下
def __init__(self, A, P, isBdDof): """ Notes ----- A: [[A00, A01], [A10, A11]] (2*gdof, 2*gdof) [[A00, A01, A02], [A10, A11, A12], [A20, A21, A22]] (3*gdof, 3*gdof) P: 预条件子 (gdof, gdof) 这里的边界条件处理放到矩阵和向量的乘积运算当中, 所心不需要修改矩阵本身 """ self.GD = len(A) self.gdof = P.shape[0] self.A = A self.isBdDof = isBdDof # 处理预条件子的边界条件 bdIdx = np.zeros(P.shape[0], dtype=np.int_) bdIdx[isBdDof] = 1 Tbd = spdiags(bdIdx, 0, P.shape[0], P.shape[0]) T = spdiags(1 - bdIdx, 0, P.shape[0], P.shape[0]) P = T @ P @ T + Tbd self.ml = pyamg.ruge_stuben_solver(P)
def solve(dmodel, uh, dirichlet=None, solver='cg'): space = uh.space start = timer() A = dmodel.get_left_matrix() b = dmodel.get_right_vector() end = timer() print("Construct linear system time:", end - start) if dirichlet is not None: AD, b = dirichlet.apply(A, b) else: AD = A if solver is 'cg': start = timer() D = AD.diagonal() M = spdiags(1/D, 0, AD.shape[0], AD.shape[1]) uh[:], info = cg(AD, b, tol=1e-14, M=M) end = timer() print(info) elif solver is 'amg': start = timer() ml = pyamg.ruge_stuben_solver(AD) uh[:] = ml.solve(b, tol=1e-12, accel='cg').reshape(-1) end = timer() print(ml) elif solver is 'direct': start = timer() uh[:] = spsolve(AD, b) end = timer() else: raise ValueError("We don't support solver `{}`! ".format(solver)) print("Solve time:", end-start) return AD, b
def solve(self, uh, timeline): ''' piccard 迭代 C-N 方法 ''' from nonlinear_robin import nonlinear_robin i = timeline.current t1 = timeline.next_time_level() dt = timeline.current_time_step_length() F = self.pde.right_vector(uh, timeline) # 网格数据 rho = self.mesh.meshdata['rho'] c = self.mesh.meshdata['c'] kappa = self.mesh.meshdata['kappa'] epsilon = self.mesh.meshdata['epsilon'] sigma = self.mesh.meshdata['sigma'] A = kappa * self.A M = rho * c * self.M b = self.apply_boundary_condition(A, F, uh, timeline) e = 0.0000000001 error = 1 xi_new = self.space.function() xi_new[:] = copy.deepcopy(uh[:, i]) while error > e: xi_tmp = copy.deepcopy(xi_new[:]) R = self.nr.robin_bc(A, xi_new, lambda x, n: self.pde.robin(x, n, t1), threshold=self.pde.is_robin_boundary) r = M @ uh[:, i] + dt * b R = M + dt * R ml = pyamg.ruge_stuben_solver(R) xi_new[:] = ml.solve(r, tol=1e-12, accel='cg').reshape(-1) # xi_new[:] = spsolve(R, b).reshape(-1) error = np.max(np.abs(xi_tmp - xi_new[:])) uh[:, i + 1] = xi_new
def Asq_solve_sandwich(self, b, S, use_pyamg=False): """ Solves A @ S @ A.T @ x = b (where A is self.get_cycle_matrix()). Parameters ---------- b : (Nf,) or (Nf, W) array Right-hand side of system. S : (Nj, Nj) sparse array Sandwich matrix. Returns ------- x : shape of b Solution of system. """ Sd = S.diagonal() if S.nnz == np.count_nonzero(Sd): if np.allclose(Sd[0], Sd): return self.Asq_solve(b) / Sd[0] if use_pyamg: import pyamg import pyamg.util.linalg A = self.cycle_matrix @ S @ self.cycle_matrix.T pyamg_cb = PyamgCallback(A, b) ml = pyamg.ruge_stuben_solver(A, strength=('classical', {'theta': 0.2})) try: mg_out = ml.solve(b, tol=1e-8, maxiter=3, callback=pyamg_cb.cb) except DivergenceError: mg_out = pyamg_cb.x if not pyamg_cb.has_diverged: return mg_out else: return self.Asq_solve_sandwich(b, S, use_pyamg=False) else: AsqF = scipy.sparse.linalg.factorized(self.cycle_matrix @ S @ self.cycle_matrix.T) return AsqF(b)
def generateQTBNQ(self): self.QTBNQ = self.QT * self.BNQ idx = list(self.QTBNQ.indices).index(0) self.QTBNQ.data[idx] *= 2.0 self.ml = pyamg.ruge_stuben_solver(self.QTBNQ)
def apply_inverse(matrix, U, options=None): """Solve linear equation system. Applies the inverse of `matrix` to the row vectors in `U`. See :func:`sparse_options` for documentation of all possible options for sparse matrices. Parameters ---------- matrix The |NumPy| matrix to invert. U 2-dimensional |NumPy array| containing as row vectors the right-hand sides of the linear equation systems to solve. options |invert_options| to use. (See :func:`invert_options`.) Returns ------- |NumPy array| of the solution vectors. """ default_options = invert_options(matrix) if options is None: options = default_options.values()[0] elif isinstance(options, str): if options == 'least_squares': for k, v in default_options.iteritems(): if k.startswith('least_squares'): options = v break assert not isinstance(options, str) else: options = default_options[options] else: assert 'type' in options and options['type'] in default_options \ and options.viewkeys() <= default_options[options['type']].viewkeys() user_options = options options = default_options[user_options['type']] options.update(user_options) R = np.empty((len(U), matrix.shape[1])) if options['type'] == 'solve': for i, UU in enumerate(U): try: R[i] = np.linalg.solve(matrix, UU) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'least_squares_lstsq': for i, UU in enumerate(U): try: R[i], _, _, _ = np.linalg.lstsq(matrix, UU, rcond=options['rcond']) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'bicgstab': for i, UU in enumerate(U): R[i], info = bicgstab(matrix, UU, tol=options['tol'], maxiter=options['maxiter']) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'bicgstab_spilu': ilu = spilu(matrix, drop_tol=options['spilu_drop_tol'], fill_factor=options['spilu_fill_factor'], drop_rule=options['spilu_drop_rule'], permc_spec=options['spilu_permc_spec']) precond = LinearOperator(matrix.shape, ilu.solve) for i, UU in enumerate(U): R[i], info = bicgstab(matrix, UU, tol=options['tol'], maxiter=options['maxiter'], M=precond) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'spsolve': for i, UU in enumerate(U): R[i] = spsolve(matrix, UU, permc_spec=options['permc_spec']) elif options['type'] == 'lgmres': for i, UU in enumerate(U): R[i], info = lgmres(matrix, UU.copy(i), tol=options['tol'], maxiter=options['maxiter'], inner_m=options['inner_m'], outer_k=options['outer_k']) if info > 0: raise InversionError('lgmres failed to converge after {} iterations'.format(info)) assert info == 0 elif options['type'] == 'least_squares_lsmr': for i, UU in enumerate(U): R[i], info, itn, _, _, _, _, _ = lsmr(matrix, UU.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], maxiter=options['maxiter'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError('lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'least_squares_lsqr': for i, UU in enumerate(U): R[i], info, itn, _, _, _, _, _, _, _ = lsqr(matrix, UU.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], iter_lim=options['iter_lim'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError('lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'pyamg': if len(U) > 0: U_iter = iter(enumerate(U)) R[0], ml = pyamg.solve(matrix, next(U_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, UU in U_iter: R[i] = pyamg.solve(matrix, UU, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg-rs': ml = pyamg.ruge_stuben_solver(matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg-sa': ml = pyamg.smoothed_aggregation_solver(matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'].startswith('generic') or options['type'].startswith('least_squares_generic'): logger = getLogger('pymor.la.numpysolvers.apply_inverse') logger.warn('You have selected a (potentially slow) generic solver for a NumPy matrix operator!') from pymor.operators.basic import NumpyMatrixOperator from pymor.la import NumpyVectorArray return genericsolvers.apply_inverse(NumpyMatrixOperator(matrix), NumpyVectorArray(U, copy=False), options=options).data else: raise ValueError('Unknown solver type') return R
import pyamg import numpy as np import scipy.sparse n = 100 omega = 1.2 A = pyamg.gallery.poisson((n, n), format='csr') # 2D Poisson problem on 500x500 grid ml = pyamg.ruge_stuben_solver(A, max_coarse=1, max_levels=100, presmoother=('jacobi', { "withrho": True, "omega": omega }), postsmoother=('jacobi', { "withrho": True, "omega": omega })) # construct the multigrid hierarchy print(ml) # print hierarchy information b = np.random.rand(A.shape[0]) # pick a random right hand side x = ml.solve(b, maxiter=2) # solve Ax=b to a tolerance of 1e-8 print("residual: ", np.linalg.norm(b - A * x)) # compute norm of residual vector def jacobi(A, x, b, omega): Ad = A.diagonal() Atmp = scipy.sparse.lil_matrix(A.shape)
def search(self, itr=False): import numpy as np if self.amg: if self.itr<0: self.itr+=1 from pyamg import ruge_stuben_solver from scipy.sparse import diags tempB = diags([self.B.tolist()] , [0]) tempy = self.y #self.C = (self.D * (self.I + self.B) ) -self.A self.C = (self.D * (self.I + tempB) ) -self.A #self.H = self.D * (tempB * self.y.T) self.H = self.D * (tempB * tempy) #self.H = self.H.todense() self.H = np.asarray(self.H) ml = ruge_stuben_solver(self.C) self.ml = ml if itr: solution = ml.solve(self.H, tol=0.5e-4, return_residuals=True) f = np.squeeze(solution[0]) x = solution[1] return (f, x) else: f = np.squeeze(ml.solve(self.H, tol=0.5e-4)) self.out = f return f else: self.ml = self.create_solver() self.out = self.ml.solve(self.H, tol=0.5e-4,x0=self.out,return_residuals=False) return self.out else: from scipy.sparse.linalg import spsolve self.C = (self.D * (self.I + self.B) ) -self.A self.H = self.D * np.dot(np.diag(self.B) , self.y.T) f = np.squeeze(spsolve(self.C, self.H)) return f
def apply_inverse(self, U, ind=None, mu=None, options=None): default_options = self.invert_options if options is None: options = default_options.values()[0] elif isinstance(options, str): options = default_options[options] else: assert 'type' in options and options['type'] in default_options \ and options.viewkeys() <= default_options[options['type']].viewkeys() user_options = options options = default_options[user_options['type']] options.update(user_options) assert isinstance(U, NumpyVectorArray) assert self.dim_range == U.dim U = U._array[:U._len] if ind is None else U._array[ind] if U.shape[1] == 0: return NumpyVectorArray(U) R = np.empty((len(U), self.dim_source)) if self.sparse: if options['type'] == 'bicgstab': for i, UU in enumerate(U): R[i], info = bicgstab(self._matrix, UU, tol=options['tol'], maxiter=options['maxiter']) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'bicgstab-spilu': ilu = spilu(self._matrix, drop_tol=options['spilu_drop_tol'], fill_factor=options['spilu_fill_factor'], drop_rule=options['spilu_drop_rule'], permc_spec=options['spilu_permc_spec']) precond = LinearOperator(self._matrix.shape, ilu.solve) for i, UU in enumerate(U): R[i], info = bicgstab(self._matrix, UU, tol=options['tol'], maxiter=options['maxiter'], M=precond) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'spsolve': for i, UU in enumerate(U): R[i] = spsolve(self._matrix, UU, permc_spec=options['permc_spec']) elif options['type'] == 'pyamg': if len(U) > 0: U_iter = iter(enumerate(U)) R[0], ml = pyamg.solve(self._matrix, next(U_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, UU in U_iter: R[i] = pyamg.solve(self._matrix, UU, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg-rs': ml = pyamg.ruge_stuben_solver(self._matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg-sa': ml = pyamg.smoothed_aggregation_solver(self._matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) else: raise ValueError('Unknown solver type') else: for i, UU in enumerate(U): try: R[i] = np.linalg.solve(self._matrix, UU) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) return NumpyVectorArray(R)
def __init__(self, A): super().__init__(A) ml = pyamg.ruge_stuben_solver(A.tocsr(), strength=('classical')) self.gamg = ml.aspreconditioner()
def alg_3_2(self, maxit=None): """ 1. 自适应求解 -\Delta u = 1。 1. 在最细网格上求最小特征值和特征向量。 refine maxit, picard: 1 """ print("算法 3.2") if maxit is None: maxit = self.maxit start = timer() if self.step == 0: idx = [] else: idx = list(range(0, self.maxit, self.step)) + [self.maxit - 1] mesh = self.pde.init_mesh(n=self.numrefine) GD = mesh.geo_dimension() if (self.step > 0) and (0 in idx): NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_2_0_' + str(NN) + '.pdf') plt.close() self.savemesh(mesh, self.resultdir + 'mesh_3_2_0_' + str(NN) + '.mat') final = 0 integrator = mesh.integrator(self.q) for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, 1) gdof = space.number_of_global_dofs() A = self.get_stiff_matrix(space) M = self.get_mass_matrix(space) b = M @ np.ones(gdof) isFreeDof = ~(space.boundary_dof()) A = A[isFreeDof, :][:, isFreeDof].tocsr() M = M[isFreeDof, :][:, isFreeDof].tocsr() uh = space.function() if self.matlab is False: uh[isFreeDof] = self.psolve(A, b[isFreeDof], M) else: uh[isFreeDof] = self.msolve(A, b[isFreeDof]) eta = self.residual_estimate(uh) markedCell = mark(eta, self.theta) IM = mesh.bisect(markedCell, returnim=True) NN = mesh.number_of_nodes() print(i + 1, "refine :", NN) if (self.step > 0) and (i in idx): fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_2_' + str(i + 1) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_2_' + str(i + 1) + '_' + str(NN) + '.mat') final = i + 1 if NN > self.maxdof: break if self.step > 0: NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_2_' + str(final) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_2_' + str(final) + '_' + str(NN) + '.mat') space = LagrangeFiniteElementSpace(mesh, 1) gdof = space.number_of_global_dofs() A = self.get_stiff_matrix(space) M = self.get_mass_matrix(space) isFreeDof = ~(space.boundary_dof()) A = A[isFreeDof, :][:, isFreeDof].tocsr() M = M[isFreeDof, :][:, isFreeDof].tocsr() if self.multieigs is True: self.A = A self.M = M self.ml = pyamg.ruge_stuben_solver(self.A) self.eigs() else: uh = IM @ uh if self.matlab is False: uh[isFreeDof], d = self.eig(A, M) else: uh[isFreeDof], d = self.meigs(A, M) print("smallest eigns:", d) return space.function(array=uh) end = timer() print("with time: ", end - start)
def perform_convergence_tests( problem, exact_sol, get_mesh, rng, verbose=False ): n = len(rng) H = numpy.empty(n) error_norm_1 = numpy.empty(n) order_1 = numpy.empty(n-1) error_norm_inf = numpy.empty(n) order_inf = numpy.empty(n-1) if verbose: print(79 * '-') print('k' + 5*' ' + 'num verts' + 4*' ' + 'max edge length' + 4*' ' + '||error||_1' + 8*' ' + '||error||_inf' ) print(38*' ' + '(order)' + 12*' ' + '(order)') print(79 * '-') # Add "zero" to all entities. This later gets translated into # np.zeros with the appropriate length, making sure that scalar # terms in the lambda expression correctly return np.arrays. zero = sympy.Symbol('zero') x = sympy.DeferredVector('x') # See <http://docs.sympy.org/dev/modules/utilities/lambdify.html>. array2array = [{'ImmutableMatrix': numpy.array}, 'numpy'] exact_eval = sympy.lambdify((x, zero), exact_sol(x), modules=array2array) for k in rng: mesh = get_mesh(k) H[k] = max(mesh.edge_lengths) linear_system = pyfvm.discretize(problem, mesh) # x = linalg.spsolve(linear_system.matrix, linear_system.rhs) ml = pyamg.ruge_stuben_solver(linear_system.matrix) x = ml.solve(linear_system.rhs, tol=1e-10) zero = numpy.zeros(len(mesh.node_coords)) error = x - exact_eval(mesh.node_coords.T, zero) # import meshio # meshio.write( # 'sol%d.vtu' % k, # mesh.node_coords, {'triangle': mesh.cells['nodes']}, # point_data={'x': x, 'error': error}, # ) error_norm_1[k] = numpy.sum(abs(mesh.control_volumes * error)) error_norm_inf[k] = max(abs(error)) # numerical orders of convergence if k > 0: order_1[k-1] = \ numpy.log(error_norm_1[k-1] / error_norm_1[k]) / \ numpy.log(H[k-1] / H[k]) order_inf[k-1] = \ numpy.log(error_norm_inf[k-1] / error_norm_inf[k]) / \ numpy.log(H[k-1] / H[k]) if verbose: print print((38*' ' + '%0.5f' + 12*' ' + '%0.5f') % (order_1[k-1], order_inf[k-1]) ) print if verbose: num_nodes = len(mesh.control_volumes) print('%2d %5.3e %0.10e %0.10e %0.10e' % (k, num_nodes, H[k], error_norm_1[k], error_norm_inf[k]) ) return H, error_norm_1, error_norm_inf, order_1, order_inf
t = time.time() res = [] x = ml.solve(b, residuals=res, tol=1e-12, accel='cg') print(res) print("residual: ", numpy.linalg.norm(b - A * x)) elapsed = time.time() - t timescale = numpy.linspace(0, elapsed, num=len(res)) plt.semilogy(timescale, res, marker='o', label='SA') print('solve time = ', elapsed) # Classical ------------------- print("****** Ruge Stuben solver ******") ml = pyamg.ruge_stuben_solver(A, max_coarse=100) print(ml) n = 0 def residual(w): global n res = A * w - b write_meshio('file%d.xdmf' % n, mesh, res) n += 1 print(numpy.linalg.norm(res)) t = time.time() res = []
# Illustrates the selection of Coarse-Fine (CF) # splittings in Classical AMG. import numpy from scipy.io import loadmat from pyamg import ruge_stuben_solver from pyamg.gallery import load_example data = loadmat('square.mat') #load_example('airfoil') A = data['A'] # matrix V = data['vertices'][:A.shape[0]] # vertices of each variable E = numpy.vstack((A.tocoo().row, A.tocoo().col)).T # edges of the matrix graph # Use Ruge-Stuben Splitting Algorithm (use 'keep' in order to retain the splitting) mls = ruge_stuben_solver(A, max_levels=2, max_coarse=1, CF='RS', keep=True) print mls # The CF splitting, 1 == C-node and 0 == F-node splitting = mls.levels[0].splitting C_nodes = splitting == 1 F_nodes = splitting == 0 from draw import lineplot from pylab import figure, axis, scatter, show figure(figsize=(6, 6)) axis('equal') lineplot(V, E) scatter(V[:, 0][C_nodes], V[:, 1][C_nodes], c='r', s=100.0) #plot C-nodes in red
for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, p=p) NDof[i] = space.number_of_global_dofs() uh = space.function() A = space.stiff_matrix() F = space.source_vector(pde.source) bc = RobinBC(space, pde.robin) A, F = bc.apply(A, F) #uh[:] = spsolve(A, F).reshape(-1) ml = pyamg.ruge_stuben_solver(A) uh[:] = ml.solve(F, tol=1e-12, accel='cg').reshape(-1) errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh) errorMatrix[1, i] = space.integralalg.L2_error(pde.gradient, uh.grad_value) if i < maxit - 1: mesh.uniform_refine() if d == 2: fig = plt.figure() axes = fig.gca(projection='3d') uh.add_plot(axes, cmap='rainbow') elif d == 3: print('The 3d function plot is not been implemented!')
def apply_inverse(op, V, options=None, least_squares=False, check_finite=True, default_solver='pyamg_solve'): """Solve linear equation system. Applies the inverse of `op` to the vectors in `rhs` using PyAMG. Parameters ---------- op The linear, non-parametric |Operator| to invert. rhs |VectorArray| of right-hand sides for the equation system. options The |solver_options| to use (see :func:`solver_options`). least_squares Must be `False`. check_finite Test if solution only contains finite values. default_solver Default solver to use (pyamg_solve, pyamg_rs, pyamg_sa). Returns ------- |VectorArray| of the solution vectors. """ assert V in op.range if least_squares: raise NotImplementedError if isinstance(op, NumpyMatrixOperator): matrix = op.matrix else: from pymor.algorithms.to_matrix import to_matrix matrix = to_matrix(op) options = _parse_options(options, solver_options(), default_solver, None, least_squares) V = V.to_numpy() promoted_type = np.promote_types(matrix.dtype, V.dtype) R = np.empty((len(V), matrix.shape[1]), dtype=promoted_type) if options['type'] == 'pyamg_solve': if len(V) > 0: V_iter = iter(enumerate(V)) R[0], ml = pyamg.solve(matrix, next(V_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, VV in V_iter: R[i] = pyamg.solve(matrix, VV, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg_rs': ml = pyamg.ruge_stuben_solver( matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg_sa': ml = pyamg.smoothed_aggregation_solver( matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) else: raise ValueError('Unknown solver type') if check_finite: if not np.isfinite(np.sum(R)): raise InversionError('Result contains non-finite values') return op.source.from_numpy(R)
def alg_3_4(self, maxit=None): """ 1. 最粗网格上求解最小特征特征值问题,得到最小特征值 d_H 和特征向量 u_H 2. 自适应求解 - \Delta u_h = u_H * u_H 插值到下一层网格上做为新 u_H 3. 最新网格层上求出的 uh 做为一个基函数,加入到最粗网格的有限元空间中, 求解最小特征值问题。 自适应 maxit, picard:2 """ print("算法 3.4") if maxit is None: maxit = self.maxit start = timer() if self.step == 0: idx = [] else: idx = list(range(0, self.maxit, self.step)) + [self.maxit - 1] mesh = self.pde.init_mesh(n=self.numrefine) integrator = mesh.integrator(self.q) # 1. 粗网格上求解最小特征值问题 space = LagrangeFiniteElementSpace(mesh, 1) AH = self.get_stiff_matrix(space) MH = self.get_mass_matrix(space) isFreeHDof = ~(space.boundary_dof()) gdof = space.number_of_global_dofs() print("initial mesh :", gdof) uH = np.zeros(gdof, dtype=np.float) A = AH[isFreeHDof, :][:, isFreeHDof].tocsr() M = MH[isFreeHDof, :][:, isFreeHDof].tocsr() if self.matlab is False: uH[isFreeHDof], d = self.eig(A, M) else: uH[isFreeHDof], d = self.meigs(A, M) uh = space.function() uh[:] = uH GD = mesh.geo_dimension() if (self.step > 0) and (0 in idx): NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_4_0_' + str(NN) + '.pdf') plt.close() self.savemesh(mesh, self.resultdir + 'mesh_3_4_0_' + str(NN) + '.mat') # 2. 以 u_H 为右端项自适应求解 -\Deta u = u_H I = eye(gdof) final = 0 for i in range(maxit): eta = self.residual_estimate(uh) markedCell = mark(eta, self.theta) IM = mesh.bisect(markedCell, returnim=True) print(i + 1, "refine :", mesh.number_of_nodes()) if (self.step > 0) and (i in idx): NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_4_' + str(i + 1) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_4_' + str(i + 1) + '_' + str(NN) + '.mat') I = IM @ I uH = IM @ uH space = LagrangeFiniteElementSpace(mesh, 1) gdof = space.number_of_global_dofs() A = self.get_stiff_matrix(space) M = self.get_mass_matrix(space) isFreeDof = ~(space.boundary_dof()) b = M @ uH uh = space.function() if self.matlab is False: uh[isFreeDof] = self.psolve( A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof], M[isFreeDof, :][:, isFreeDof].tocsr()) else: uh[isFreeDof] = self.msolve( A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof]) final = i + 1 if gdof > self.maxdof: break if self.step > 0: NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_4_' + str(final) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_4_' + str(final) + '_' + str(NN) + '.mat') # 3. 把 uh 加入粗网格空间, 组装刚度和质量矩阵 w0 = uh @ A w1 = w0 @ uh w2 = w0 @ I AA = bmat([[AH, w2.reshape(-1, 1)], [w2, w1]], format='csr') w0 = uh @ M w1 = w0 @ uh w2 = w0 @ I MM = bmat([[MH, w2.reshape(-1, 1)], [w2, w1]], format='csr') isFreeDof = np.r_[isFreeHDof, True] u = np.zeros(len(isFreeDof)) ## 求解特征值 A = AA[isFreeDof, :][:, isFreeDof].tocsr() M = MM[isFreeDof, :][:, isFreeDof].tocsr() if self.multieigs is True: self.A = A self.M = M self.ml = pyamg.ruge_stuben_solver(self.A) self.eigs() else: if self.matlab is False: u[isFreeDof], d = self.eig(A, M) else: u[isFreeDof], d = self.meigs(A, M) print("smallest eigns:", d) uh *= u[-1] uh += I @ u[:-1] uh /= np.max(np.abs(uh)) uh = space.function(array=uh) return uh end = timer() print("with time: ", end - start)
def alg_3_3(self, maxit=None): """ 1. 最粗网格上求解最小特征特征值问题,得到最小特征值 d_H 和特征向量 u_H 2. 自适应求解 - \Delta u_h = u_H * u_H 插值到下一层网格上做为新 u_H 3. 在最细网格上求解一次最小特征值问题 自适应 maxit, picard:2 """ print("算法 3.3") if maxit is None: maxit = self.maxit start = timer() if self.step == 0: idx = [] else: idx = list(range(0, self.maxit, self.step)) mesh = self.pde.init_mesh(n=self.numrefine) # 1. 粗网格上求解最小特征值问题 space = LagrangeFiniteElementSpace(mesh, 1) AH = self.get_stiff_matrix(space) MH = self.get_mass_matrix(space) isFreeHDof = ~(space.boundary_dof()) gdof = space.number_of_global_dofs() uH = np.zeros(gdof, dtype=mesh.ftype) print("initial mesh :", gdof) A = AH[isFreeHDof, :][:, isFreeHDof].tocsr() M = MH[isFreeHDof, :][:, isFreeHDof].tocsr() if self.matlab is False: uH[isFreeHDof], d = self.eig(A, M) else: uH[isFreeHDof], d = self.meigs(A, M) uh = space.function() uh[:] = uH GD = mesh.geo_dimension() if (self.step > 0) and (0 in idx): NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_3_0_' + str(NN) + '.pdf') plt.close() self.savemesh(mesh, self.resultdir + 'mesh_3_3_0_' + str(NN) + '.mat') # 2. 以 u_H 为右端项自适应求解 -\Deta u = u_H I = eye(gdof) final = 0 for i in range(maxit - 1): eta = self.residual_estimate(uh) markedCell = mark(eta, self.theta) IM = mesh.bisect(markedCell, returnim=True) NN = mesh.number_of_nodes() print(i + 1, "refine : ", NN) if (self.step > 0) and (i in idx): NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_3_' + str(i + 1) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_3_' + str(i + 1) + '_' + str(NN) + '.mat') final = i + 1 if NN > self.maxdof: break I = IM @ I uH = IM @ uH space = LagrangeFiniteElementSpace(mesh, 1) gdof = space.number_of_global_dofs() A = self.get_stiff_matrix(space) M = self.get_mass_matrix(space) isFreeDof = ~(space.boundary_dof()) b = M @ uH uh = space.function() if self.matlab is False: uh[isFreeDof] = self.psolve( A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof], M[isFreeDof, :][:, isFreeDof].tocsr()) else: uh[isFreeDof] = self.msolve( A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof]) # 3. 在最细网格上求解一次最小特征值问题 if self.step > 0: NN = mesh.number_of_nodes() fig = plt.figure() fig.set_facecolor('white') if GD == 2: axes = fig.gca() else: axes = Axes3D(fig) mesh.add_plot(axes, cellcolor='w') fig.savefig(self.resultdir + 'mesh_3_3_' + str(final) + '_' + str(NN) + '.pdf') plt.close() self.savemesh( mesh, self.resultdir + 'mesh_3_3_' + str(final) + '_' + str(NN) + '.mat') space = LagrangeFiniteElementSpace(mesh, 1) gdof = space.number_of_global_dofs() A = self.get_stiff_matrix(space) M = self.get_mass_matrix(space) isFreeDof = ~(space.boundary_dof()) uh = space.function(array=uh) A = A[isFreeDof, :][:, isFreeDof].tocsr() M = M[isFreeDof, :][:, isFreeDof].tocsr() uh = space.function() if self.multieigs is True: self.A = A self.M = M self.ml = pyamg.ruge_stuben_solver(self.A) self.eigs() else: if self.matlab is False: uh[isFreeDof], d = self.eig(A, M) else: uh[isFreeDof], d = self.meigs(A, M) print("smallest eigns:", d) return uh end = timer() print("with time: ", end - start)
def apply_inverse(op, V, options=None, least_squares=False, check_finite=True, default_solver='pyamg_solve'): """Solve linear equation system. Applies the inverse of `op` to the vectors in `rhs` using PyAMG. Parameters ---------- op The linear, non-parametric |Operator| to invert. rhs |VectorArray| of right-hand sides for the equation system. options The |solver_options| to use (see :func:`solver_options`). check_finite Test if solution only containes finite values. default_solver Default solver to use (pyamg_solve, pyamg_rs, pyamg_sa). Returns ------- |VectorArray| of the solution vectors. """ assert V in op.range if isinstance(op, NumpyMatrixOperator): matrix = op._matrix else: from pymor.algorithms.to_matrix import to_matrix matrix = to_matrix(op) options = _parse_options(options, solver_options(), default_solver, None, least_squares) V = V.data promoted_type = np.promote_types(matrix.dtype, V.dtype) R = np.empty((len(V), matrix.shape[1]), dtype=promoted_type) if options['type'] == 'pyamg_solve': if len(V) > 0: V_iter = iter(enumerate(V)) R[0], ml = pyamg.solve(matrix, next(V_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, VV in V_iter: R[i] = pyamg.solve(matrix, VV, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg_rs': ml = pyamg.ruge_stuben_solver(matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg_sa': ml = pyamg.smoothed_aggregation_solver(matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) else: raise ValueError('Unknown solver type') if check_finite: if not np.isfinite(np.sum(R)): raise InversionError('Result contains non-finite values') return op.source.from_data(R)
# Illustrates the selection of Coarse-Fine (CF) # splittings in Classical AMG. import numpy from pyamg import ruge_stuben_solver from scipy.io import loadmat from scipy.io import savemat data = loadmat('Mat/NcutData.mat') Acsc = data['NcutMatrix'] # matrix Acsr = Acsc.tocsr() mls = ruge_stuben_solver(Acsr, max_levels=6, max_coarse=150, CF='RS', keep=True) #mls = ruge_stuben_solver(Acsr, keep=True) ''' Parameters #---------- A : csr_matrix Square matrix in CSR format strength : ['symmetric', 'classical', 'evolution', None] Method used to determine the strength of connection between unknowns of the linear system. Method-specific parameters may be passed in using a tuple, e.g. strength=('symmetric',{'theta' : 0.25 }). If strength=None, all nonzero entries of the matrix are considered strong. CF : {string} : default 'RS' Method used for coarse grid selection (C/F splitting) Supported methods are RS, PMIS, PMISc, CLJP, and CLJPc presmoother : {string or dict} Method used for presmoothing at each level. Method-specific parameters
def apply_inverse(matrix, U, options=None): """Solve linear equation system. Applies the inverse of `matrix` to the row vectors in `U`. See :func:`sparse_options` for documentation of all possible options for sparse matrices. This method is called by :meth:`pymor.core.NumpyMatrixOperator.apply_inverse` and usually should not be used directly. Parameters ---------- matrix The |NumPy| matrix to invert. U 2-dimensional |NumPy array| containing as row vectors the right-hand sides of the linear equation systems to solve. options |invert_options| to use. (See :func:`invert_options`.) Returns ------- |NumPy array| of the solution vectors. """ default_options = invert_options(matrix) if options is None: options = default_options.values()[0] elif isinstance(options, str): if options == 'least_squares': for k, v in default_options.iteritems(): if k.startswith('least_squares'): options = v break assert not isinstance(options, str) else: options = default_options[options] else: assert 'type' in options and options['type'] in default_options \ and options.viewkeys() <= default_options[options['type']].viewkeys() user_options = options options = default_options[user_options['type']] options.update(user_options) R = np.empty((len(U), matrix.shape[1])) if options['type'] == 'solve': for i, UU in enumerate(U): try: R[i] = np.linalg.solve(matrix, UU) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'least_squares_lstsq': for i, UU in enumerate(U): try: R[i], _, _, _ = np.linalg.lstsq(matrix, UU, rcond=options['rcond']) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'bicgstab': for i, UU in enumerate(U): R[i], info = bicgstab(matrix, UU, tol=options['tol'], maxiter=options['maxiter']) if info != 0: if info > 0: raise InversionError( 'bicgstab failed to converge after {} iterations'. format(info)) else: raise InversionError( 'bicgstab failed with error code {} (illegal input or breakdown)' .format(info)) elif options['type'] == 'bicgstab_spilu': ilu = spilu(matrix, drop_tol=options['spilu_drop_tol'], fill_factor=options['spilu_fill_factor'], drop_rule=options['spilu_drop_rule'], permc_spec=options['spilu_permc_spec']) precond = LinearOperator(matrix.shape, ilu.solve) for i, UU in enumerate(U): R[i], info = bicgstab(matrix, UU, tol=options['tol'], maxiter=options['maxiter'], M=precond) if info != 0: if info > 0: raise InversionError( 'bicgstab failed to converge after {} iterations'. format(info)) else: raise InversionError( 'bicgstab failed with error code {} (illegal input or breakdown)' .format(info)) elif options['type'] == 'spsolve': if scipy.version.version >= '0.14': if hasattr(matrix, 'factorization'): R = matrix.factorization.solve(U.T).T elif options['keep_factorization']: matrix.factorization = splu(matrix, permc_spec=options['permc_spec']) R = matrix.factorization.solve(U.T).T else: R = spsolve(matrix, U.T, permc_spec=options['permc_spec']).T else: if hasattr(matrix, 'factorization'): for i, UU in enumerate(U): R[i] = matrix.factorization.solve(UU) elif options['keep_factorization']: matrix.factorization = splu(matrix, permc_spec=options['permc_spec']) for i, UU in enumerate(U): R[i] = matrix.factorization.solve(UU) elif len(U) > 1: factorization = splu(matrix, permc_spec=options['permc_spec']) for i, UU in enumerate(U): R[i] = factorization.solve(UU) else: R = spsolve(matrix, U.T, permc_spec=options['permc_spec']).reshape((1, -1)) elif options['type'] == 'lgmres': for i, UU in enumerate(U): R[i], info = lgmres(matrix, UU.copy(i), tol=options['tol'], maxiter=options['maxiter'], inner_m=options['inner_m'], outer_k=options['outer_k']) if info > 0: raise InversionError( 'lgmres failed to converge after {} iterations'.format( info)) assert info == 0 elif options['type'] == 'least_squares_lsmr': for i, UU in enumerate(U): R[i], info, itn, _, _, _, _, _ = lsmr(matrix, UU.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], maxiter=options['maxiter'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError( 'lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'least_squares_lsqr': for i, UU in enumerate(U): R[i], info, itn, _, _, _, _, _, _, _ = lsqr( matrix, UU.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], iter_lim=options['iter_lim'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError( 'lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'pyamg': if len(U) > 0: U_iter = iter(enumerate(U)) R[0], ml = pyamg.solve(matrix, next(U_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, UU in U_iter: R[i] = pyamg.solve(matrix, UU, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg-rs': ml = pyamg.ruge_stuben_solver(matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg-sa': ml = pyamg.smoothed_aggregation_solver( matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, UU in enumerate(U): R[i] = ml.solve(UU, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'].startswith('generic') or options['type'].startswith( 'least_squares_generic'): logger = getLogger('pymor.la.numpysolvers.apply_inverse') logger.warn( 'You have selected a (potentially slow) generic solver for a NumPy matrix operator!' ) from pymor.operators.numpy import NumpyMatrixOperator from pymor.la.numpyvectorarray import NumpyVectorArray return genericsolvers.apply_inverse(NumpyMatrixOperator(matrix), NumpyVectorArray(U, copy=False), options=options).data else: raise ValueError('Unknown solver type') return R
def _solve(self, A=None, b=None, x0=None): r""" Sends the A and b matrices to the specified solver, and solves for *x* given the boundary conditions, and source terms based on the present value of *x*. This method does NOT iterate to solve for non-linear source terms or march time steps. Parameters ---------- A : sparse matrix The coefficient matrix in sparse format. If not specified, then it uses the ``A`` matrix attached to the object. b : ND-array The RHS matrix in any format. If not specified, then it uses the ``b`` matrix attached to the object. x0 : ND-array The initial guess for the solution of Ax = b Notes ----- The solver used here is specified in the ``settings`` attribute of the algorithm. """ # Fetch A and b from self if not given, and throw error if not found A = self.A if A is None else A b = self.b if b is None else b if A is None or b is None: raise Exception('The A matrix or the b vector not yet built.') A = A.tocsr() x0 = np.zeros_like(b) if x0 is None else x0 # Check if A and b are well-defined self._check_for_nans() # Raise error if solver_family not available if self.settings["solver_family"] not in ["scipy", "petsc", "pyamg"]: raise Exception(f"{self.settings['solver_family']} not available.") # Set tolerance for iterative solvers tol = self.settings["solver_tol"] max_it = self.settings["solver_maxiter"] atol = self._get_atol() rtol = self._get_rtol(x0=x0) # Check if A is symmetric is_sym = op.utils.is_symmetric(self.A) if self.settings['solver_type'] == 'cg' and not is_sym: raise Exception('CG solver only works on symmetric matrices.') # SciPy if self.settings['solver_family'] == 'scipy': # Umfpack by default uses its 32-bit build -> memory overflow try: import scikits.umfpack A.indices = A.indices.astype(np.int64) A.indptr = A.indptr.astype(np.int64) except ModuleNotFoundError: pass solver = getattr(scipy.sparse.linalg, self.settings['solver_type']) iterative = [ 'bicg', 'bicgstab', 'cg', 'cgs', 'gmres', 'lgmres', 'minres', 'gcrotmk', 'qmr' ] if solver.__name__ in iterative: x, exit_code = solver(A=A, b=b, atol=atol, tol=tol, maxiter=max_it, x0=x0) if exit_code > 0: raise Exception( f'Solver did not converge, exit code: {exit_code}') else: x = solver(A=A, b=b) # PETSc if self.settings['solver_family'] == 'petsc': # Check if petsc is available try: import petsc4py from openpnm.utils.petsc import PETScSparseLinearSolver as SLS except Exception: raise ModuleNotFoundError('PETSc is not installed.') temp = { "type": self.settings["solver_type"], "preconditioner": self.settings["solver_preconditioner"] } ls = SLS(A=A, b=b, settings=temp) x = ls.solve(x0=x0, atol=atol, rtol=rtol, max_it=max_it) # PyAMG if self.settings['solver_family'] == 'pyamg': # Check if PyAMG is available try: import pyamg except Exception: raise ModuleNotFoundError('PyAMG is not installed.') ml = pyamg.ruge_stuben_solver(A) x = ml.solve(b=b, tol=rtol, maxiter=max_it) return x
""" Test the convergence of a 100x100 anisotropic diffusion equation """ import numpy as np import pyamg n = 100 nx = n ny = n # Rotated Anisotropic Diffusion stencil = pyamg.gallery.diffusion_stencil_2d( type='FE', epsilon=0.001, theta=np.pi / 3) A = pyamg.gallery.stencil_grid(stencil, (nx, ny), format='csr') S = pyamg.strength.classical_strength_of_connection(A, 0.0) np.random.seed(625) x = np.random.rand(A.shape[0]) b = A * np.random.rand(A.shape[0]) ml = pyamg.ruge_stuben_solver(A, max_coarse=10) resvec = [] x = ml.solve(b, x0=x, maxiter=20, tol=1e-14, residuals=resvec) for i, r in enumerate(resvec): print("residual at iteration {0:2}: {1:^6.2e}".format(i, r))
def _solve(self, A=None, b=None): r""" Sends the A and b matrices to the specified solver, and solves for *x* given the boundary conditions, and source terms based on the present value of *x*. This method does NOT iterate to solve for non-linear source terms or march time steps. Parameters ---------- A : sparse matrix The coefficient matrix in sparse format. If not specified, then it uses the ``A`` matrix attached to the object. b : ND-array The RHS matrix in any format. If not specified, then it uses the ``b`` matrix attached to the object. Notes ----- The solver used here is specified in the ``settings`` attribute of the algorithm. """ # Fetch A and b from self if not given, and throw error if they've not # been calculated if A is None: A = self.A if A is None: raise Exception('The A matrix has not been built yet') if b is None: b = self.b if b is None: raise Exception('The b matrix has not been built yet') A = A.tocsr() # Default behavior -> use Scipy's default solver (spsolve) if self.settings['solver'] == 'pyamg': self.settings['solver_family'] = 'pyamg' if self.settings['solver'] == 'petsc': self.settings['solver_family'] = 'petsc' # Set tolerance for iterative solvers rtol = self.settings['solver_rtol'] # Reference for residual's normalization ref = np.sum(np.absolute(self.A.diagonal())) or 1 atol = ref * rtol # SciPy if self.settings['solver_family'] == 'scipy': if importlib.util.find_spec('scikit-umfpack'): A.indices = A.indices.astype(np.int64) A.indptr = A.indptr.astype(np.int64) iterative = ['bicg', 'bicgstab', 'cg', 'cgs', 'gmres', 'lgmres', 'minres', 'gcrotmk', 'qmr'] solver = getattr(sprs.linalg, self.settings['solver_type']) if self.settings['solver_type'] in iterative: x, exit_code = solver(A=A, b=b, atol=atol, tol=rtol, maxiter=self.settings['solver_maxiter']) if exit_code > 0: raise Exception('SciPy solver did not converge! ' + 'Exit code: ' + str(exit_code)) else: x = solver(A=A, b=b) return x # PETSc if self.settings['solver_family'] == 'petsc': # Check if petsc is available if importlib.util.find_spec('petsc4py'): from openpnm.utils.petsc import PETScSparseLinearSolver as SLS else: raise Exception('PETSc is not installed.') # Define the petsc linear system converting the scipy objects ls = SLS(A=A, b=b) sets = self.settings sets = {k: v for k, v in sets.items() if k.startswith('solver_')} sets = {k.split('solver_')[1]: v for k, v in sets.items()} ls.settings.update(sets) x = SLS.solve(ls) del(ls) return x # PyAMG if self.settings['solver_family'] == 'pyamg': if importlib.util.find_spec('pyamg'): import pyamg else: raise Exception('pyamg is not installed.') ml = pyamg.ruge_stuben_solver(A) x = ml.solve(b=b, tol=1e-10) return x
def _apply_inverse(matrix, V, options=None): """Solve linear equation system. Applies the inverse of `matrix` to the row vectors in `V`. See :func:`dense_options` for documentation of all possible options for sparse matrices. See :func:`sparse_options` for documentation of all possible options for sparse matrices. This method is called by :meth:`pymor.core.NumpyMatrixOperator.apply_inverse` and usually should not be used directly. Parameters ---------- matrix The |NumPy| matrix to invert. V 2-dimensional |NumPy array| containing as row vectors the right-hand sides of the linear equation systems to solve. options The solver options to use. (See :func:`_options`.) Returns ------- |NumPy array| of the solution vectors. """ default_options = _options(matrix) if options is None: options = default_options.values()[0] elif isinstance(options, str): if options == 'least_squares': for k, v in default_options.iteritems(): if k.startswith('least_squares'): options = v break assert not isinstance(options, str) else: options = default_options[options] else: assert 'type' in options and options['type'] in default_options \ and options.viewkeys() <= default_options[options['type']].viewkeys() user_options = options options = default_options[user_options['type']] options.update(user_options) promoted_type = np.promote_types(matrix.dtype, V.dtype) R = np.empty((len(V), matrix.shape[1]), dtype=promoted_type) if options['type'] == 'solve': for i, VV in enumerate(V): try: R[i] = np.linalg.solve(matrix, VV) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'least_squares_lstsq': for i, VV in enumerate(V): try: R[i], _, _, _ = np.linalg.lstsq(matrix, VV, rcond=options['rcond']) except np.linalg.LinAlgError as e: raise InversionError('{}: {}'.format(str(type(e)), str(e))) elif options['type'] == 'bicgstab': for i, VV in enumerate(V): R[i], info = bicgstab(matrix, VV, tol=options['tol'], maxiter=options['maxiter']) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'bicgstab_spilu': ilu = spilu(matrix, drop_tol=options['spilu_drop_tol'], fill_factor=options['spilu_fill_factor'], drop_rule=options['spilu_drop_rule'], permc_spec=options['spilu_permc_spec']) precond = LinearOperator(matrix.shape, ilu.solve) for i, VV in enumerate(V): R[i], info = bicgstab(matrix, VV, tol=options['tol'], maxiter=options['maxiter'], M=precond) if info != 0: if info > 0: raise InversionError('bicgstab failed to converge after {} iterations'.format(info)) else: raise InversionError('bicgstab failed with error code {} (illegal input or breakdown)'. format(info)) elif options['type'] == 'spsolve': try: # maybe remove unusable factorization: if hasattr(matrix, 'factorization'): fdtype = matrix.factorizationdtype if not np.can_cast(V.dtype, fdtype, casting='safe'): del matrix.factorization if map(int, scipy.version.version.split('.')) >= [0, 14, 0]: if hasattr(matrix, 'factorization'): # we may use a complex factorization of a real matrix to # apply it to a real vector. In that case, we downcast # the result here, removing the imaginary part, # which should be zero. R = matrix.factorization.solve(V.T).T.astype(promoted_type, copy=False) elif options['keep_factorization']: # the matrix is always converted to the promoted type. # if matrix.dtype == promoted_type, this is a no_op matrix.factorization = splu(matrix_astype_nocopy(matrix, promoted_type), permc_spec=options['permc_spec']) matrix.factorizationdtype = promoted_type R = matrix.factorization.solve(V.T).T else: # the matrix is always converted to the promoted type. # if matrix.dtype == promoted_type, this is a no_op R = spsolve(matrix_astype_nocopy(matrix, promoted_type), V.T, permc_spec=options['permc_spec']).T else: # see if-part for documentation if hasattr(matrix, 'factorization'): for i, VV in enumerate(V): R[i] = matrix.factorization.solve(VV).astype(promoted_type, copy=False) elif options['keep_factorization']: matrix.factorization = splu(matrix_astype_nocopy(matrix, promoted_type), permc_spec=options['permc_spec']) matrix.factorizationdtype = promoted_type for i, VV in enumerate(V): R[i] = matrix.factorization.solve(VV) elif len(V) > 1: factorization = splu(matrix_astype_nocopy(matrix, promoted_type), permc_spec=options['permc_spec']) for i, VV in enumerate(V): R[i] = factorization.solve(VV) else: R = spsolve(matrix_astype_nocopy(matrix, promoted_type), V.T, permc_spec=options['permc_spec']).reshape((1, -1)) except RuntimeError as e: raise InversionError(e) elif options['type'] == 'lgmres': for i, VV in enumerate(V): R[i], info = lgmres(matrix, VV.copy(i), tol=options['tol'], maxiter=options['maxiter'], inner_m=options['inner_m'], outer_k=options['outer_k']) if info > 0: raise InversionError('lgmres failed to converge after {} iterations'.format(info)) assert info == 0 elif options['type'] == 'least_squares_lsmr': for i, VV in enumerate(V): R[i], info, itn, _, _, _, _, _ = lsmr(matrix, VV.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], maxiter=options['maxiter'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError('lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'least_squares_lsqr': for i, VV in enumerate(V): R[i], info, itn, _, _, _, _, _, _, _ = lsqr(matrix, VV.copy(i), damp=options['damp'], atol=options['atol'], btol=options['btol'], conlim=options['conlim'], iter_lim=options['iter_lim'], show=options['show']) assert 0 <= info <= 7 if info == 7: raise InversionError('lsmr failed to converge after {} iterations'.format(itn)) elif options['type'] == 'pyamg': if len(V) > 0: V_iter = iter(enumerate(V)) R[0], ml = pyamg.solve(matrix, next(V_iter)[1], tol=options['tol'], maxiter=options['maxiter'], return_solver=True) for i, VV in V_iter: R[i] = pyamg.solve(matrix, VV, tol=options['tol'], maxiter=options['maxiter'], existing_solver=ml) elif options['type'] == 'pyamg-rs': ml = pyamg.ruge_stuben_solver(matrix, strength=options['strength'], CF=options['CF'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], coarse_solver=options['coarse_solver']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'] == 'pyamg-sa': ml = pyamg.smoothed_aggregation_solver(matrix, symmetry=options['symmetry'], strength=options['strength'], aggregate=options['aggregate'], smooth=options['smooth'], presmoother=options['presmoother'], postsmoother=options['postsmoother'], improve_candidates=options['improve_candidates'], max_levels=options['max_levels'], max_coarse=options['max_coarse'], diagonal_dominance=options['diagonal_dominance']) for i, VV in enumerate(V): R[i] = ml.solve(VV, tol=options['tol'], maxiter=options['maxiter'], cycle=options['cycle'], accel=options['accel']) elif options['type'].startswith('generic') or options['type'].startswith('least_squares_generic'): logger = getLogger('pymor.operators.numpy._apply_inverse') logger.warn('You have selected a (potentially slow) generic solver for a NumPy matrix operator!') from pymor.operators.numpy import NumpyMatrixOperator from pymor.vectorarrays.numpy import NumpyVectorArray return genericsolvers.apply_inverse(NumpyMatrixOperator(matrix), NumpyVectorArray(V, copy=False), options=options).data else: raise ValueError('Unknown solver type') return R
def testgrid(parameters): exec ','.join(parameters) + ', = parameters.values()' # unpack the parameters into the local namespace description = '-' + description dt = 24.0*7 #hours per time step Nsteps = 1 #number of steps Nx = problemscale #number of cells, x-dimension Ny = problemscale Nz = problemscale ndims = 3 N = Nx*Ny*Nz #number of cells, total size=N if verbose: print "N is %i." % N #h in feet hx=16.0 #length, x-dimension hy=16.0 hz=10.0 #perm in md, conversion factor for hours Perm =ones([3,Nz,Ny,Nx]).astype(np.float64)*100.0*.0002637 #mD is millidarcy=m^2/1000 #permeability Kinv = 1.0/Perm phi = .20 #unitless #porosity ct = 10.0E-06 #1/psi #conductivity? #B=1.0 alpha = hx*hy*hz*phi*ct/dt #ft^3/hours/psi #??? gamma = .433 #psi/ft #specific weight Phi =ones([Nz,Ny,Nx]).astype(np.float64)*2500.0 #Flow Potential Z=zeros([Nz,Ny,Nx]).astype(np.float64) for k in range(Nz): Z[k,:,:]+=k*hz # 3D field of all 0's in the bottom slice (z=0), adding 10 for each slice up (all 10s in slice where z=1, all 20s in slice where z=2, etc.) p = Phi-gamma*Z #potential Phi = Phi.flatten() #Phi is now just a row vector of 2500.0's, either Nx or Ny long. Really? Not Nx*Ny*Nz? # We're switching from using a 3-tuple as an index to each cell to having a scalar between 0 and (N-1) as an index to each cell. TX = zeros([Nz,Ny,Nx+1]).astype(np.float64)#zeros([Nx+1,Ny,Nz]) #a 3D scalar field: x-components of transmissibility vectors TY = zeros([Nz,Ny+1,Nx]).astype(np.float64)#zeros([Nx,Ny+1,Nz]) TZ = zeros([Nz+1,Ny,Nx]).astype(np.float64)#zeros([Nx,Ny,Nz+1]) # (for Nx=3,Ny=4,Nz=5): TX[:,:,1:-1] = (2*hy*hz/hx)/(Kinv[0,:,:,0:-1]+Kinv[0,:,:,1: ]) # 2x4x5 TY[:,1:-1,:] = (2*hx*hz/hy)/(Kinv [1,:,0:-1,:]+Kinv[1,:,1:,:]) # 3x3x5 Why are these not all 3x4x5? TZ[1:-1,:,:] = (2*hx*hy/hz)/(Kinv[2,0:-1,:,:]+Kinv[2,1:,:,:]) # 3x4x4 x1 = TX[:,:,0:Nx].flatten() x2 = TX[:,:,1:].flatten() y1 = TY[:,0:Ny,:].flatten() y2 = TY[:,1:,:].flatten() z1 = TZ[0:Nz,:,:].flatten() z2 = TZ[1:,:,:].flatten() q = zeros([Nz,Ny,Nx]).astype(np.float64) q[:,4,4]=10.0*5.61/24.0 Iw = (Nx*Ny-1)/2 q = q.flatten() main_diag=x1+x2+y1+y2+z1+z2#+q2 #(when q2==1, sum is zero and vice versa) #DiagVecs = vstack((-z2,-y2,-x2,main_diag,-x1,-y1,-z1)) DiagVecs = vstack((-z2,-y2,-x2, -x1,-y1,-z1)) #DiagIndx = array([-Nx*Ny,-Nx,-1,0,1,Nx,Nx*Ny]) DiagIndx = array([-Nx*Ny,-Nx,-1,1, Nx,Nx*Ny]) Phi_w = zeros(Nsteps+1).astype(np.float64) Phi_w[0] = Phi[Iw] Phi_c = zeros(Nsteps+1).astype(np.float64) Phi_c[0] = Phi[-1] Phi_cl = zeros(Nsteps+1).astype(np.float64) Phi_cl[0] = Phi[0] level=0 #whoami() #global N #global ndims A = sparse.spdiags(DiagVecs,DiagIndx,N/(2**ndims)**level,N/(2**ndims)**level,format='csr') DM = sparse.spdiags(main_diag,array([0]),N/(2**ndims)**level,N/(2**ndims)**level,format='csr') D0 = sparse.spdiags(ones(N/(2**ndims)**level)*alpha,array([0]),N/(2**ndims)**level,N/(2**ndims)**level,format='csr') A = sparse.spdiags(DiagVecs,DiagIndx,N/(2**ndims)**level,N/(2**ndims)**level,format='csr') DM = sparse.spdiags(main_diag,array([0]),N/(2**ndims)**level,N/(2**ndims)**level,format='csr') D0 = sparse.spdiags(ones(N/(2**ndims)**level)*alpha,array([0]),N/(2**ndims)**level,N/(2**ndims)**level,format='csr') LHS = (A+D0+DM).toarray().astype(np.float64) if verbose: print 'LHS shape is:' print LHS.shape # Main Timestep Loop info_dict = {'test_grid':True} for k in range(Nsteps): Qa = (-A.astype(np.float64)*Phi.astype(np.float64)).astype(np.float64) Qa-= DM*Phi if verbose: print 'solving with %s...' % solver ##CHOOSE THY SOLVER: if solver == 'pyamg': ##PyAMG: Ruge-Steuben #make_sparsity_graph('graphs/pyamg_LHS.png','pyamg LHS',A+D0+DM) ml = pyamg.ruge_stuben_solver(A+D0+DM,max_levels=gridlevels,presmoother=('gauss_seidel',{'iterations':iterations})) u = ml.solve(q+Qa,cycle='F',tol=1e-06, accel='cg') info_dict['solverstring']='PyAMG-%icells' % N info_dict['cycle']=0 info_dict['norm']=np.linalg.norm(q+Qa-np.dot(LHS,u)) if solver == 'pyamg-linagg': ##PyAMG; linear aggregation: #make_sparsity_graph('graphs/pyamg_LHS.png','pyamg LHS',A+D0+DM) ml=pyamg.smoothed_aggregation_solver(A+D0+DM)#,mat_flag= 'symmetric',strength= 'symmetric') u = ml.solve(q+Qa,cycle='F',tol=1e-06, accel='cg') info_dict['solverstring']='PyAMG-%icells' % N info_dict['cycle']=0 info_dict['norm']=np.linalg.norm(q+Qa-np.dot(LHS,u)) elif solver == 'mmg': ##Our Multi-Multi-Grid #parameters['verbose']=False #uncomment to disable verbosity within the OpenMG code. if graph_pressure: parameters['cycles']=1 (u,info_dict) = mg_solve(LHS,q+Qa,parameters) # info_dict here contains both cycle and norm if graph_pressure: parameters['cycles']=2 if graph_pressure: (utwo,info_dict) = mg_solve(LHS,q+Qa,parameters) # info_dict here contains both cycle and norm if graph_pressure: parameters['cycles']=3 if graph_pressure: (uthree,info_dict) = mg_solve(LHS,q+Qa,parameters) # info_dict here contains both cycle and norm info_dict['solverstring'] = '%igrid-%iiter-%icells%sthreshold-%icycles' % (gridlevels,iterations,N,threshold,cycles) elif solver == 'gs': ##Our Gauss-Seidel iterative solver (u,gs_iterations) = iterative_solve_to_threshold(LHS, q+Qa, np.zeros((q.size,)), threshold,verbose=verbose) info_dict['solverstring']='GaussSeidel-%iiter-%icells' % (gs_iterations,N) info_dict['cycle']=0 info_dict['norm']=np.linalg.norm(q+Qa-np.dot(LHS,u)) elif solver == 'gs_xiter': ##Our Gauss-Seidel iterative solver, with a specified number of iterations #def iterative_solve(A,b,x,iterations,verbose=False): u = iterative_solve(LHS, q+Qa, np.zeros((q.size,)), iterations,verbose) info_dict={} gs_iterations = iterations info_dict['solverstring']='GaussSeidel-%iiter-%icells' % (gs_iterations,N) info_dict['cycle']=0 info_dict['norm']=np.linalg.norm(q+Qa-np.dot(LHS,u)) else: ##Numpy's (pretty good) direct solver. solver = 'direct' u = np.linalg.solve(LHS,q+Qa) info_dict['solverstring']= 'direct-%icells' % N info_dict['cycle']=0 info_dict['norm']=np.linalg.norm(q+Qa-np.dot(LHS,u)) if graph_pressure: oldPhi = Phi.copy() Phi += u Phi_w[k+1]=Phi[Iw] Phi_cl[k+1]=Phi[0] Phi_c[k+1]=Phi[-1] info_dict['solverstring'] += description if graph_pressure: u_correct = np.linalg.solve(LHS,q+Qa) Phi_correct = oldPhi + u_correct Phi_graph_correct = reshape(Phi_correct,[Nz,Ny,Nx]) Phi_two = oldPhi + utwo Phi_two_graph=reshape(Phi_two,[Nz,Ny,Nx]) Phi_three = oldPhi + uthree Phi_three_graph=reshape(Phi_three,[Nz,Ny,Nx]) Phi_graph=reshape(Phi,[Nz,Ny,Nx]) filename='graphs/USS_output-%s.png' % (info_dict['solverstring'],) import visualization as viz viz.make_multiple_3d_graphs([Phi_graph_correct.T,Phi_graph.T,Phi_two_graph.T,Phi_three_graph.T],filename) del [Phi,Phi_c,Phi_cl,Phi_graph,Phi_w,u,Qa,DM,D0,LHS,A] else: del [Phi,Phi_c,Phi_cl,Phi_w,u,Qa,DM,D0,LHS,A] if verbose: print "completed solverstring is", info_dict['solverstring'] return info_dict
def test_block_diagonalize_P(): """Check if eigenvalues of block matrices are the same as eigenvalues of original block-circulant matrix""" init_octave(1) num_unknowns_per_block = 64 root_num_blocks = 3 A, _ = generate_A_delaunay_block_periodic_lognormal( num_unknowns_per_block, root_num_blocks) # A = A + 0.1 * scipy.sparse.diags(np.ones(num_unknowns_per_block * root_num_blocks**2)) orig_solver = pyamg.ruge_stuben_solver(A, max_levels=2, max_coarse=1, CF='CLJP', keep=True) orig_splitting = orig_solver.levels[0].splitting block_splitting = list(chunks(orig_splitting, num_unknowns_per_block)) common_block_splitting = most_frequent_splitting(block_splitting) repeated_splitting = np.tile(common_block_splitting, root_num_blocks**2) # we recompute the Ruge-Stuben prolongation matrix with the modified splitting, and the original strength # matrix. We assume the strength matrix is block-circulant (because A is block-circulant) C = orig_solver.levels[0].C P = direct_interpolation(A, C, repeated_splitting) P = tf.convert_to_tensor(P.toarray(), dtype=tf.float64) P_blocks = block_diagonalize_P(P, root_num_blocks, repeated_splitting.nonzero()) P_blocks = P_blocks.numpy() A_c = P.numpy().T @ A.toarray() @ P.numpy() # double_W, double_W_conj_t = create_double_W(num_unknowns_per_block * root_num_blocks, root_num_blocks) # A_c_full_block_diag = double_W_conj_t @ A_c_full @ double_W # P_full_block_diag = double_W_conj_t @ full_P @ double_W # A_block_diag = double_W_conj_t @ A.toarray() @ double_W # A_c_full_block_diag_2 = P_full_block_diag.conj().T @ A_block_diag @ P_full_block_diag tf_A = tf.cast(tf.stack([A.toarray()]), tf.complex128) A_blocks = block_diagonalize_A_fast( tf_A, root_num_blocks, True).numpy()[0][1:] # ignore the first zero mode block def relaxation_matrices(As, w=0.8): I = np.eye(As[0].shape[0]) res = [I - w * np.diag(1 / (np.diag(A))) @ A for A in As] # computes the iteration matrix of the relaxation, here Gauss-Seidel is used. # This function is called on each block seperately. # num_As = len(As) # grid_sizes = [A.shape[0] for A in As] # Bs = [A.copy() for A in As] # for B, grid_size in zip(Bs, grid_sizes): # B[np.tril_indices(grid_size, 0)[0], np.tril_indices(grid_size, 0)[1]] = 0. # B is the upper part of A # res = [] # for i in tqdm(range(num_As)): # range(A.shape[0] // batch_size): # res.append(scipy.linalg.solve_triangular(a=As[i], # b=-Bs[i], # lower=True, unit_diagonal=False, # overwrite_b=False, debug=None, check_finite=True).astype( # np.float64)) return res S = relaxation_matrices([A.toarray()])[0] S_blocks = relaxation_matrices(A_blocks) # A_c = P.numpy().T @ A.toarray() @ P.numpy() A_c_blocks = P_blocks.transpose([0, 2, 1]).conj() @ A_blocks @ P_blocks A = A.toarray() C = np.eye(A.shape[0]) - P.numpy() @ np.linalg.inv(A_c) @ P.numpy().T @ A M = S @ C @ S I = np.eye(A_blocks[0].shape[0]) C_blocks = [ I - P_block @ np.linalg.inv(A_c_block) @ P_block.conj().T @ A_block for (P_block, A_c_block, A_block) in zip(P_blocks, A_c_blocks, A_blocks) ] M_blocks = [ S_block @ C_block @ S_block for (S_block, C_block) in zip(S_blocks, C_blocks) ] # # extract only elements that correspond to coarse nodes # A_c_blocks = A_c_blocks[:, common_block_splitting.nonzero()[0][:, None], common_block_splitting.nonzero()[0]] A_c_block_eigs = np.sort(np.linalg.eigvals(A_c_blocks).flatten()) A_c_eigs = np.sort(np.linalg.eigvals(A_c)) C_block_eigs = np.sort(np.linalg.eigvals(C_blocks).flatten()) C_eigs = np.sort(np.linalg.eigvals(C)) M_block_eigs = np.sort(np.linalg.eigvals(M_blocks).flatten()) M_eigs = np.sort(np.linalg.eigvals(M)) pass
# Illustrates the selection of Coarse-Fine (CF) # splittings in Classical AMG. import numpy from scipy.io import loadmat from pyamg import ruge_stuben_solver from pyamg.gallery import load_example data = loadmat('square.mat') #load_example('airfoil') A = data['A'] # matrix V = data['vertices'][:A.shape[0]] # vertices of each variable E = numpy.vstack((A.tocoo().row,A.tocoo().col)).T # edges of the matrix graph # Use Ruge-Stuben Splitting Algorithm (use 'keep' in order to retain the splitting) mls = ruge_stuben_solver(A, max_levels=2, max_coarse=1, CF='RS',keep=True) print mls # The CF splitting, 1 == C-node and 0 == F-node splitting = mls.levels[0].splitting C_nodes = splitting == 1 F_nodes = splitting == 0 from draw import lineplot from pylab import figure, axis, scatter, show figure(figsize=(6,6)) axis('equal') lineplot(V, E) scatter(V[:,0][C_nodes], V[:,1][C_nodes], c='r', s=100.0) #plot C-nodes in red scatter(V[:,0][F_nodes], V[:,1][F_nodes], c='b', s=100.0) #plot F-nodes in blue
def _apply_inverse(matrix, V, options=None): """Solve linear equation system. Applies the inverse of `matrix` to the row vectors in `V`. See :func:`dense_options` for documentation of all possible options for sparse matrices. See :func:`sparse_options` for documentation of all possible options for sparse matrices. This method is called by :meth:`pymor.core.NumpyMatrixOperator.apply_inverse` and usually should not be used directly. Parameters ---------- matrix The |NumPy| matrix to invert. V 2-dimensional |NumPy array| containing as row vectors the right-hand sides of the linear equation systems to solve. options The solver options to use. (See :func:`_options`.) Returns ------- |NumPy array| of the solution vectors. """ default_options = _options(matrix) if options is None: options = default_options.values()[0] elif isinstance(options, str): if options == "least_squares": for k, v in default_options.iteritems(): if k.startswith("least_squares"): options = v break assert not isinstance(options, str) else: options = default_options[options] else: assert ( "type" in options and options["type"] in default_options and options.viewkeys() <= default_options[options["type"]].viewkeys() ) user_options = options options = default_options[user_options["type"]] options.update(user_options) R = np.empty((len(V), matrix.shape[1]), dtype=np.promote_types(matrix.dtype, V.dtype)) if options["type"] == "solve": for i, VV in enumerate(V): try: R[i] = np.linalg.solve(matrix, VV) except np.linalg.LinAlgError as e: raise InversionError("{}: {}".format(str(type(e)), str(e))) elif options["type"] == "least_squares_lstsq": for i, VV in enumerate(V): try: R[i], _, _, _ = np.linalg.lstsq(matrix, VV, rcond=options["rcond"]) except np.linalg.LinAlgError as e: raise InversionError("{}: {}".format(str(type(e)), str(e))) elif options["type"] == "bicgstab": for i, VV in enumerate(V): R[i], info = bicgstab(matrix, VV, tol=options["tol"], maxiter=options["maxiter"]) if info != 0: if info > 0: raise InversionError("bicgstab failed to converge after {} iterations".format(info)) else: raise InversionError("bicgstab failed with error code {} (illegal input or breakdown)".format(info)) elif options["type"] == "bicgstab_spilu": ilu = spilu( matrix, drop_tol=options["spilu_drop_tol"], fill_factor=options["spilu_fill_factor"], drop_rule=options["spilu_drop_rule"], permc_spec=options["spilu_permc_spec"], ) precond = LinearOperator(matrix.shape, ilu.solve) for i, VV in enumerate(V): R[i], info = bicgstab(matrix, VV, tol=options["tol"], maxiter=options["maxiter"], M=precond) if info != 0: if info > 0: raise InversionError("bicgstab failed to converge after {} iterations".format(info)) else: raise InversionError("bicgstab failed with error code {} (illegal input or breakdown)".format(info)) elif options["type"] == "spsolve": try: if scipy.version.version >= "0.14": if hasattr(matrix, "factorization"): R = matrix.factorization.solve(V.T).T elif options["keep_factorization"]: matrix.factorization = splu(matrix, permc_spec=options["permc_spec"]) R = matrix.factorization.solve(V.T).T else: R = spsolve(matrix, V.T, permc_spec=options["permc_spec"]).T else: if hasattr(matrix, "factorization"): for i, VV in enumerate(V): R[i] = matrix.factorization.solve(VV) elif options["keep_factorization"]: matrix.factorization = splu(matrix, permc_spec=options["permc_spec"]) for i, VV in enumerate(V): R[i] = matrix.factorization.solve(VV) elif len(V) > 1: factorization = splu(matrix, permc_spec=options["permc_spec"]) for i, VV in enumerate(V): R[i] = factorization.solve(VV) else: R = spsolve(matrix, V.T, permc_spec=options["permc_spec"]).reshape((1, -1)) except RuntimeError as e: raise InversionError(e) elif options["type"] == "lgmres": for i, VV in enumerate(V): R[i], info = lgmres( matrix, VV.copy(i), tol=options["tol"], maxiter=options["maxiter"], inner_m=options["inner_m"], outer_k=options["outer_k"], ) if info > 0: raise InversionError("lgmres failed to converge after {} iterations".format(info)) assert info == 0 elif options["type"] == "least_squares_lsmr": for i, VV in enumerate(V): R[i], info, itn, _, _, _, _, _ = lsmr( matrix, VV.copy(i), damp=options["damp"], atol=options["atol"], btol=options["btol"], conlim=options["conlim"], maxiter=options["maxiter"], show=options["show"], ) assert 0 <= info <= 7 if info == 7: raise InversionError("lsmr failed to converge after {} iterations".format(itn)) elif options["type"] == "least_squares_lsqr": for i, VV in enumerate(V): R[i], info, itn, _, _, _, _, _, _, _ = lsqr( matrix, VV.copy(i), damp=options["damp"], atol=options["atol"], btol=options["btol"], conlim=options["conlim"], iter_lim=options["iter_lim"], show=options["show"], ) assert 0 <= info <= 7 if info == 7: raise InversionError("lsmr failed to converge after {} iterations".format(itn)) elif options["type"] == "pyamg": if len(V) > 0: V_iter = iter(enumerate(V)) R[0], ml = pyamg.solve( matrix, next(V_iter)[1], tol=options["tol"], maxiter=options["maxiter"], return_solver=True ) for i, VV in V_iter: R[i] = pyamg.solve(matrix, VV, tol=options["tol"], maxiter=options["maxiter"], existing_solver=ml) elif options["type"] == "pyamg-rs": ml = pyamg.ruge_stuben_solver( matrix, strength=options["strength"], CF=options["CF"], presmoother=options["presmoother"], postsmoother=options["postsmoother"], max_levels=options["max_levels"], max_coarse=options["max_coarse"], coarse_solver=options["coarse_solver"], ) for i, VV in enumerate(V): R[i] = ml.solve( VV, tol=options["tol"], maxiter=options["maxiter"], cycle=options["cycle"], accel=options["accel"] ) elif options["type"] == "pyamg-sa": ml = pyamg.smoothed_aggregation_solver( matrix, symmetry=options["symmetry"], strength=options["strength"], aggregate=options["aggregate"], smooth=options["smooth"], presmoother=options["presmoother"], postsmoother=options["postsmoother"], improve_candidates=options["improve_candidates"], max_levels=options["max_levels"], max_coarse=options["max_coarse"], diagonal_dominance=options["diagonal_dominance"], ) for i, VV in enumerate(V): R[i] = ml.solve( VV, tol=options["tol"], maxiter=options["maxiter"], cycle=options["cycle"], accel=options["accel"] ) elif options["type"].startswith("generic") or options["type"].startswith("least_squares_generic"): logger = getLogger("pymor.operators.numpy._apply_inverse") logger.warn("You have selected a (potentially slow) generic solver for a NumPy matrix operator!") from pymor.operators.numpy import NumpyMatrixOperator from pymor.vectorarrays.numpy import NumpyVectorArray return genericsolvers.apply_inverse( NumpyMatrixOperator(matrix), NumpyVectorArray(V, copy=False), options=options ).data else: raise ValueError("Unknown solver type") return R
# 25, 25, 25 # ) # mesh = pyfvm.meshTetra.meshTetra(vertices, cells) # vertices, cells = meshzoo.rectangle.create_mesh( # 0.0, 2.0, # 0.0, 1.0, # 401, 201, # zigzag=True # ) # mesh = pyfvm.meshTri.meshTri(vertices, cells) import mshr import dolfin h = 2.5e-2 # cell_size = 2 * pi / num_boundary_points c = mshr.Circle(dolfin.Point(0., 0., 0.), 1, int(2*pi / h)) # cell_size = 2 * bounding_box_radius / res m = mshr.generate_mesh(c, 2.0 / h) coords = m.coordinates() coords = numpy.c_[coords, numpy.zeros(len(coords))] mesh = pyfvm.meshTri.meshTri(coords, m.cells()) linear_system = pyfvm.discretize(Poisson(), mesh) ml = pyamg.ruge_stuben_solver(linear_system.matrix) x = ml.solve(linear_system.rhs, tol=1e-10) # from scipy.sparse import linalg # x = linalg.spsolve(linear_system.matrix, linear_system.rhs) mesh.write('out.vtu', point_data={'x': x})
def generateQTBNQ(self): self.QTBNQ = self.QT*self.BNQ idx = list(self.QTBNQ.indices).index(0) self.QTBNQ.data[idx] *=2.0 self.ml = pyamg.ruge_stuben_solver(self.QTBNQ)