def solver_pcg_amg(A): """ Return a function for solving a sparse linear system using PCG with AMG. Parameters ---------- A : (N, N) array_like Input. Returns ------- solve : callable To solve the linear system of equations given in `A`, the `solve` callable should be passed an ndarray of shape (N,). """ from scipy.sparse.linalg import cg from pyamg import rootnode_solver M = rootnode_solver(A.T).aspreconditioner(cycle='V') def solver(b, x0=None): x, info = cg(A.T, b, x0=x0, M=M) if info != 0: raise ValueError(f'CG failed: info={info}') return x return solver,
def __init__(self, linear_op: LinearOperator, heuristic: str = 'ruge_stuben', cycle: str = 'F', n_cycles: int = 1, **kwargs): """ Abstract representation for Algebraic Multi-grid (AMG) class of preconditioners. Available heuristics are the one from the PyAMG Python library. :param linear_op: Linear operator to build the algebraic multi-grid preconditioner on. :param heuristic: Name of the algebraic multi-grid heuristic used for multi-level hierarchy construction. :param cycle: Type of cycle of the multigrid method, either "V", "W", "F" or "AMLI". :param n_cycles: Number of cycles done per application of the multi-grid method as a preconditioner. """ # Sanitize the heuristic argument if heuristic not in ['ruge_stuben', 'smoothed_aggregated', 'rootnode']: raise PreconditionerError( 'AMG heuristic {} unknown.'.format(heuristic)) matrix_repr = linear_op.mat # Setup multi-grid hierarchical structure with corresponding heuristic if heuristic == 'ruge_stuben': self.amg = pyamg.ruge_stuben_solver(matrix_repr.tocsr(), **kwargs) elif heuristic == 'smoothed_aggregated': self.amg = pyamg.smoothed_aggregation_solver( matrix_repr.tocsr(), **kwargs) elif heuristic == 'rootnode': self.amg = pyamg.rootnode_solver(matrix_repr.tocsr(), **kwargs) # Sanitize the number of cycles argument if not isinstance(n_cycles, int) or n_cycles < 1: raise PreconditionerError( 'Number of cycles must be a positive integer, received {}.'. format(n_cycles)) # Sanitize the cycle argument if cycle not in ['V', 'F', 'W', 'AMLI']: raise PreconditionerError( 'AMG cycle type {} unknown.'.format(cycle)) self.cycle = cycle self.n_cycles = n_cycles # Get hierarchy key attributes self.cycle_complexity = self.amg.cycle_complexity(cycle=self.cycle) self.operator_complexity = self.amg.operator_complexity() self.levels = self.amg.levels self.amg = self.amg.aspreconditioner(cycle=self.cycle) super().__init__(linear_op)
def build_pyamg(self, A): try: import pyamg except: raise ImportError(f"*** pyamg not found {self.linearsolver=} ***") # return pyamg.smoothed_aggregation_solver(A) B = np.ones((A.shape[0], 1)) B = pyamg.solver_configuration(A, verb=False)['B'] if self.convection: symmetry = 'nonsymmetric' # smoother = 'gauss_seidel_nr' smoother = 'gauss_seidel' smoother = 'block_gauss_seidel' smoother = 'strength_based_schwarz' smoother = 'schwarz' # smoother = 'own_gs' # smoother = 'gmres' # global setup_own_gs # def setup_own_gs(lvl, iterations=2, sweep='forward'): # def smoother(A, x, b): # pyamg.relaxation.gauss_seidel(A, x, b, iterations=iterations, sweep=sweep) # # return smoother # smoother = 'own_gs' # smooth = ('energy', {'krylov': 'fgmres'}) smooth = ('energy', {'krylov': 'bicgstab'}) # improve_candidates =[ (smoother, {'sweep': 'symmetric', 'iterations': 4}), None] improve_candidates = None else: symmetry = 'hermitian' smooth = ('energy', {'krylov': 'cg'}) smoother = 'gauss_seidel' # improve_candidates =[ ('gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), None] improve_candidates = None # strength = [('evolution', {'k': 2, 'epsilon': 10.0})] strength = [('symmetric', {'theta': 0.05})] psmoother = (smoother, {'sweep': 'symmetric', 'iterations': 1}) # psmoother = (smoother, {'maxiter': 10}) SA_build_args = { 'max_levels': 10, 'max_coarse': 25, 'coarse_solver': 'pinv2', 'symmetry': symmetry, 'smooth': smooth, 'strength': strength, 'presmoother': psmoother, 'presmoother': psmoother, 'improve_candidates': improve_candidates, 'diagonal_dominance': False } # return pyamg.smoothed_aggregation_solver(A, B, **SA_build_args) return pyamg.rootnode_solver(A, B, **SA_build_args)
def _linear_analysis(self, method, **kwargs): """Performs the linear analysis, in which the pressure and flow fields are computed. INPUT: method: This can be either 'direct' or 'iterative' **kwargs precision: The accuracy to which the ls is to be solved. If not supplied, machine accuracy will be used. (This only applies to the iterative solver) OUTPUT: The maximum, mean, and median pressure change. Moreover, pressure and flow are modified in-place. """ G = self._G A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, self._b) elif method == 'iterative': if kwargs.has_key('precision'): eps = kwargs['precision'] else: eps = self._eps AA = smoothed_aggregation_solver(A, max_levels=10, max_coarse=500) x = abs(AA.solve(self._b, x0=None, tol=eps, accel='cg', cycle='V', maxiter=150)) # abs required, as (small) negative pressures may arise elif method == 'iterative2': # Set linear solver ml = rootnode_solver(A, smooth=('energy', {'degree':2}), strength='evolution' ) M = ml.aspreconditioner(cycle='V') # Solve pressure system #x,info = gmres(A, self._b, tol=self._eps, maxiter=50, M=M, x0=self._x) #x,info = gmres(A, self._b, tol=self._eps/10000000000000, maxiter=50, M=M) x,info = gmres(A, self._b, tol=self._eps/10000, maxiter=50, M=M) if info != 0: print('SOLVEERROR in Solving the Matrix') pdiff = map(abs, [(p - xx) / p if p > 0 else 0.0 for p, xx in zip(G.vs['pressure'], x)]) maxPDiff = max(pdiff) meanPDiff = np.mean(pdiff) medianPDiff = np.median(pdiff) log.debug(np.nonzero(np.array(pdiff) == maxPDiff)[0]) G.vs['pressure'] = x G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - \ G.vs[edge.target]['pressure']) * \ edge['conductance'] for edge in G.es] self._maxPDiff=maxPDiff self._meanPDiff=meanPDiff self._medianPDiff=medianPDiff return maxPDiff, meanPDiff, medianPDiff
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, **kwargs): try: import pyamg except: raise ImportError(f"*** pyamg not found ***") self.method = 'pyamg' self.matvec = A nsmooth = kwargs.pop('nsmooth', 1) self.smoother = kwargs.pop('smoother', 'schwarz') symmetric = kwargs.pop('symmetric', False) self.type = kwargs.pop('pyamgtype', 'aggregation') self.accel = kwargs.pop('accel', None) if self.accel == 'none': self.accel = None pyamgargs = {'B': pyamg.solver_configuration(A, verb=False)['B']} smoother = (self.smoother, { 'sweep': 'symmetric', 'iterations': nsmooth }) if symmetric: smooth = ('energy', {'krylov': 'cg'}) else: smooth = ('energy', {'krylov': 'fgmres'}) pyamgargs['symmetry'] = 'nonsymmetric' pyamgargs['presmoother'] = smoother pyamgargs['postsmoother'] = smoother # pyamgargs['smooth'] = smooth # pyamgargs['coarse_solver'] = 'splu' if self.type == 'aggregation': self.mlsolver = pyamg.smoothed_aggregation_solver(A, **pyamgargs) elif self.type == 'rootnode': self.mlsolver = pyamg.rootnode_solver(A, **pyamgargs) else: raise ValueError(f"unknown {self.type=}") self.solver = self.mlsolver.solve # cycle : {'V','W','F','AMLI'} super().__init__(**kwargs) self.args['cycle'] = 'V' self.args['accel'] = self.accel
def solve(self, method): """Solves the linear system A x = b for the vector of unknown pressures x, either using a direct solver (obsolete) or an iterative GMRES solver. From the pressures, the flow field is computed. INPUT: method: This can be either 'direct' or 'iterative2' OUTPUT: None - G is modified in place. G_final.pkl & G_final.vtp: are save as output sampledict.pkl: is saved as output """ b = self._b A = self._A G = self._G htt2htd = self._P.tube_to_discharge_hematocrit A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, b) elif method == 'iterative2': ml = rootnode_solver(A, smooth=('energy', {'degree':2}), strength='evolution' ) M = ml.aspreconditioner(cycle='V') # Solve pressure system x,info = gmres(A, self._b, tol=1000*self._eps, maxiter=200, M=M) if info != 0: print('ERROR in Solving the Matrix') print(info) G.vs['pressure'] = x G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - G.vs[edge.target]['pressure']) * \ edge['conductance'] for edge in G.es] #Default Units - mmHg for pressure G.vs['pressure'] = [v['pressure']/self._scalingFactor for v in G.vs] if self._withRBC: G.es['v']=[e['htd']/e['htt']*e['flow']/(0.25*np.pi*e['diameter']**2) for e in G.es] else: G.es['v']=[e['flow']/(0.25*np.pi*e['diameter']**2) for e in G.es]
print "Test convergence for a simple 200x200 Grid, Linearized Elasticity Problem" choice = input('\n Input Choice:\n' + \ '1: Run smoothed_aggregation_solver\n' + \ '2: Run rootnode_solver\n' ) # Create matrix and candidate vectors. B has 3 columns, representing # rigid body modes of the mesh. B[:,0] and B[:,1] are translations in # the X and Y directions while B[:,2] is a rotation. A, B = linear_elasticity((200, 200), format='bsr') # Construct solver using AMG based on Smoothed Aggregation (SA) if choice == 1: mls = smoothed_aggregation_solver(A, B=B, smooth='energy') elif choice == 2: mls = rootnode_solver(A, B=B, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") # Display hierarchy information print mls # Create random right hand side b = scipy.rand(A.shape[0], 1) # Solve Ax=b residuals = [] x = mls.solve(b, tol=1e-10, residuals=residuals) print "Number of iterations: %d\n" % len(residuals) # Output convergence
''' Example driver script for solver_diagnostics.py, which tries different parameter combinations for smoothed_aggregation_solver(...) and rootnode_solver(...). The goal is to find appropriate parameter settings for an arbitrary matrix. Explore 4 different matrices: CSR matrix for basic isotropic diffusion CSR matrix for basic rotated anisotropic diffusion BSR matrix for basic 2D linearized elasticity CSR matrix for a nonsymmetric recirculating flow problem Many more solver parameters may be specified than outlined in the below examples. Only the most basic are shown. Run with >>> python demo.py and examine the on-screen output and file output. ''' from scipy import pi from pyamg import gallery from pyamg.gallery import diffusion stencil = diffusion.diffusion_stencil_2d(type='FE', epsilon=0.001, theta=2 * pi / 16.0) A = gallery.stencil_grid(stencil, (50, 50), format='csr') from pyamg import gallery from solver_diagnostics import solver_diagnostics from scipy import pi from pyamg.gallery import diffusion
""" import numpy as np import pyamg from convergence_tools import print_cycle_history n = 100 print("Test convergence for a simple 100x100 Grid, Gauge Laplacian") choice = input('\n Input Choice:\n' + '1: Run smoothed_aggregation_solver\n' + '2: Run rootnode_solver\n') np.random.seed(625) A = pyamg.gallery.gauge_laplacian(n, beta=0.001) x = np.random.rand(A.shape[0]) + 1.0j * np.random.rand(A.shape[0]) b = np.random.rand(A.shape[0]) + 1.0j * np.random.rand(A.shape[0]) choice = int(choice) if choice == 1: ml = pyamg.smoothed_aggregation_solver(A, smooth='energy') elif choice == 2: ml = pyamg.rootnode_solver(A, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") 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))
## # Construct solver and solve if choice == 1: sa_symmetric = pyamg.smoothed_aggregation_solver(A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) elif choice == 2: sa_symmetric = pyamg.rootnode_solver(A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) else: raise ValueError("Enter a choice of 1 or 2") sa_symmetric = pyamg.smoothed_aggregation_solver(A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) resvec = [] x = sa_symmetric.solve(b, x0=x0, residuals=resvec, **SA_solve_args)
SA_build_args={'max_levels':10, 'max_coarse':25, 'coarse_solver':'pinv2', \ 'symmetry':'hermitian'} SA_solve_args={'cycle':'V', 'maxiter':15, 'tol':1e-8} strength=[('evolution', {'k':2, 'epsilon':4.0})] presmoother =('gauss_seidel', {'sweep':'symmetric', 'iterations':1}) postsmoother=('gauss_seidel', {'sweep':'symmetric', 'iterations':1}) ## # Construct solver and solve if choice == 1: sa_symmetric = smoothed_aggregation_solver(A, B=B, smooth=smooth, \ strength=strength, presmoother=presmoother, \ postsmoother=postsmoother, **SA_build_args) elif choice == 2: sa_symmetric = rootnode_solver(A, B=B, smooth=smooth, \ strength=strength, presmoother=presmoother, \ postsmoother=postsmoother, **SA_build_args) else: raise ValueError("Enter a choice of 1 or 2") sa_symmetric = smoothed_aggregation_solver(A, B=B, smooth=smooth, \ strength=strength, presmoother=presmoother, \ postsmoother=postsmoother, **SA_build_args) resvec = [] x = sa_symmetric.solve(b, x0=x0, residuals=resvec, **SA_solve_args) print "\nObserve that standard SA parameters for Hermitian systems\n" + \ "yield a nonconvergent stand-alone solver.\n" print_cycle_history(resvec, sa_symmetric, verbose=True, plotting=False) ##
def solve(self, method, **kwargs): """Solves the linear system A x = b for the vector of unknown pressures x, either using a direct solver (obsolete) or an iterative GMRES solver. From the pressures, the flow field is computed. INPUT: method: This can be either 'direct' or 'iterative2' OUTPUT: None - G is modified in place. G_final.pkl & G_final.vtp: are save as output sampledict.pkl: is saved as output """ b = self._b G = self._G htt2htd = self._P.tube_to_discharge_hematocrit A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, b) elif method == 'iterative2': ml = rootnode_solver(A, smooth=('energy', { 'degree': 2 }), strength='evolution') M = ml.aspreconditioner(cycle='V') # Solve pressure system #x,info = gmres(A, self._b, tol=self._eps, maxiter=1000, M=M) x, info = gmres(A, self._b, tol=10 * self._eps, M=M) if info != 0: print('ERROR in Solving the Matrix') print(info) G.vs['pressure'] = x self._x = x conductance = self._conductance G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - G.vs[edge.target]['pressure']) * \ conductance[i] for i, edge in enumerate(G.es)] #Default Units - mmHg for pressure for v in G.vs: v['pressure'] = v['pressure'] / vgm.units.scaling_factor_du( 'mmHg', G['defaultUnits']) if self._withRBC: G.es['v'] = [ e['htd'] / e['htt'] * e['flow'] / (0.25 * np.pi * e['diameter']**2) for e in G.es ] else: G.es['v'] = [ e['flow'] / (0.25 * np.pi * e['diameter']**2) for e in G.es ] #Convert 'pBC' from default Units to mmHg pBCneNone = G.vs(pBC_ne=None).indices G.vs[pBCneNone]['pBC'] = np.array(G.vs[pBCneNone]['pBC']) * ( 1 / vgm.units.scaling_factor_du('mmHg', G['defaultUnits'])) vgm.write_pkl(G, 'G_final.pkl') vgm.write_vtp(G, 'G_final.vtp', False) #Write Output sampledict = {} for eprop in ['flow', 'v']: if not eprop in sampledict.keys(): sampledict[eprop] = [] sampledict[eprop].append(G.es[eprop]) for vprop in ['pressure']: if not vprop in sampledict.keys(): sampledict[vprop] = [] sampledict[vprop].append(G.vs[vprop]) g_output.write_pkl(sampledict, 'sampledict.pkl')
import numpy import scipy from pyamg.gallery import gauge_laplacian from pyamg import smoothed_aggregation_solver, rootnode_solver from convergence_tools import print_cycle_history if __name__ == '__main__': n = 100 print "Test convergence for a simple 100x100 Grid, Gauge Laplacian" choice = input('\n Input Choice:\n' + \ '1: Run smoothed_aggregation_solver\n' + \ '2: Run rootnode_solver\n' ) numpy.random.seed(625) A = gauge_laplacian(n, beta=0.001) x = scipy.rand(A.shape[0]) + 1.0j * scipy.rand(A.shape[0]) b = scipy.rand(A.shape[0]) + 1.0j * scipy.rand(A.shape[0]) if choice == 1: sa = smoothed_aggregation_solver(A, smooth='energy') elif choice == 2: sa = rootnode_solver(A, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") resvec = [] x = sa.solve(b, x0=x, maxiter=20, tol=1e-14, residuals=resvec) print_cycle_history(resvec, sa, verbose=True, plotting=True)
## # Construct solver and solve if choice == 1: sa_symmetric = pyamg.smoothed_aggregation_solver( A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) elif choice == 2: sa_symmetric = pyamg.rootnode_solver( A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) else: raise ValueError("Enter a choice of 1 or 2") sa_symmetric = pyamg.smoothed_aggregation_solver( A, B=B, smooth=smooth, strength=strength, presmoother=presmoother, postsmoother=postsmoother, **SA_build_args) resvec = []
def _linear_analysis(self, method, **kwargs): """Performs the linear analysis, in which the pressure and flow fields are computed. INPUT: method: This can be either 'direct' or 'iterative' **kwargs precision: The accuracy to which the ls is to be solved. If not supplied, machine accuracy will be used. (This only applies to the iterative solver) OUTPUT: The maximum, mean, and median pressure change. Moreover, pressure and flow are modified in-place. """ G = self._G A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, self._b) elif method == 'iterative': if kwargs.has_key('precision'): eps = kwargs['precision'] else: eps = self._eps AA = smoothed_aggregation_solver(A, max_levels=10, max_coarse=500) x = abs( AA.solve(self._b, x0=None, tol=eps, accel='cg', cycle='V', maxiter=150)) # abs required, as (small) negative pressures may arise elif method == 'iterative2': # Set linear solver ml = rootnode_solver(A, smooth=('energy', { 'degree': 2 }), strength='evolution') M = ml.aspreconditioner(cycle='V') # Solve pressure system #x,info = gmres(A, self._b, tol=self._eps, maxiter=50, M=M, x0=self._x) #x,info = gmres(A, self._b, tol=self._eps/10000000000000, maxiter=50, M=M) x, info = gmres(A, self._b, tol=self._eps / 10000, maxiter=50, M=M) if info != 0: print('SOLVEERROR in Solving the Matrix') pdiff = map(abs, [(p - xx) / p if p > 0 else 0.0 for p, xx in zip(G.vs['pressure'], x)]) maxPDiff = max(pdiff) meanPDiff = np.mean(pdiff) medianPDiff = np.median(pdiff) log.debug(np.nonzero(np.array(pdiff) == maxPDiff)[0]) G.vs['pressure'] = x G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - \ G.vs[edge.target]['pressure']) * \ edge['conductance'] for edge in G.es] self._maxPDiff = maxPDiff self._meanPDiff = meanPDiff self._medianPDiff = medianPDiff return maxPDiff, meanPDiff, medianPDiff
from pyamg.gallery import gauge_laplacian from pyamg import smoothed_aggregation_solver, rootnode_solver from convergence_tools import print_cycle_history if __name__ == '__main__': n = 100 print "Test convergence for a simple 100x100 Grid, Gauge Laplacian" choice = input('\n Input Choice:\n' + \ '1: Run smoothed_aggregation_solver\n' + \ '2: Run rootnode_solver\n' ) numpy.random.seed(625) A = gauge_laplacian(n, beta=0.001) x = scipy.rand(A.shape[0]) + 1.0j*scipy.rand(A.shape[0]) b = scipy.rand(A.shape[0]) + 1.0j*scipy.rand(A.shape[0]) if choice == 1: sa = smoothed_aggregation_solver(A, smooth='energy') elif choice == 2: sa = rootnode_solver(A, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") resvec = [] x = sa.solve(b, x0=x, maxiter=20, tol=1e-14, residuals=resvec) print_cycle_history(resvec, sa, verbose=True, plotting=True)
def solve(self, solver="lu", x0=None, tol=1.e-6): solver = solver.lower() sf = 1e30 pores = self.network.pores A = self.csr_solver_matrix self.solver_matrix.set_csr_singular_rows_to_dirichlet(A) self.A = A mass_residual = 1.0 if x0 is not None: self.sol[:] = x0 if solver == "lu": lu_A = splu(A) elif solver == "amg": ml = pyamg.rootnode_solver(A, max_coarse=10) elif solver == "petsc": comm = MPI.COMM_SELF ksp = get_petsc_ksp(A=A * sf, ksptype="minres", tol=tol, max_it=1000) petsc_rhs = PETSc.Vec().createWithArray(self.rhs * sf, comm=comm) elif "trilinos" in solver: epetra_mat = matrix_scipy_to_epetra(A * sf) epetra_rhs = vector_numpy_to_epetra(self.rhs * sf) if "ml" in solver: epetra_prec = trilinos_ml_prec(epetra_mat) def inner_loop_solve(tol): if solver == "lu": self.sol[:] = lu_A.solve(self.rhs) elif solver == "amg": self.sol[:] = ml.solve(b=self.rhs, x0=self.sol, tol=tol, accel='gmres') elif solver == "petsc": ksp.setTolerances(rtol=tol) ksp.setFromOptions() petsc_sol = PETSc.Vec().createWithArray(self.sol, comm=comm) ksp.setInitialGuessNonzero(True) ksp.solve(petsc_rhs, petsc_sol) self.sol[:] = petsc_sol.getArray() elif "trilinos" in solver: epetra_sol = vector_numpy_to_epetra(self.sol) if "ml" in solver: x = trilinos_solve(epetra_mat, epetra_rhs, epetra_prec, x=epetra_sol, tol=tol) else: x = solve_aztec(epetra_mat, epetra_rhs, x=epetra_sol, tol=tol) self.sol[:] = x pores.p_w[:] = self.sol[:] # This side-effect is required for the compute_mass_residual function pores.p_n[:] = pores.p_w + pores.p_c count = 0 while (mass_residual > 1e-5) and (count < 100): count += 1 inner_loop_solve(tol) mass_residual = self.compute_mass_residual(A, self.rhs, self.sol) logger.debug("Mass flux residual %e", mass_residual) if count == 99: logger.warn("Failed to converge. Residual %e. Falling back to mltrilinos solver", mass_residual) return self.solve(solver="mltrilinos") # Fall back to reliable solver tol /= 10.0 if "ml" in solver: epetra_prec.DestroyPreconditioner(); return np.copy(self.sol)
presmoother=prepost, postsmoother=prepost, smooth=smooth, strength=('evolution', {'epsilon': evolution_theta, 'k': 2})) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_evo[run] = (resvec[-1] / resvec[0])**(1.0 / len(resvec)) complexity_evo[run] = ml.operator_complexity() nnz_evo[run] = A.nnz sizelist_evo[run] = A.shape[0] # Evolution strength measure ml = pyamg.rootnode_solver(A, max_coarse=mcoarse, coarse_solver='pinv2', presmoother=prepost, postsmoother=prepost, smooth=smooth, strength=('evolution', {'epsilon': evolution_theta, 'k': 2})) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_evo_root[run] = (resvec[-1] / resvec[0])**(1.0 / len(resvec)) complexity_evo_root[run] = ml.operator_complexity() nnz_evo_root[run] = A.nnz sizelist_evo_root[run] = A.shape[0] run += 1 # Print Problem Description print("\nAMG Scalability Study for Ax = 0, x_init = rand\n") print("Emphasis on Robustness of Evolution Strength ")
def fixed_stress(gb, A, b, block_dof, full_dof, x0=None): """ Fixed stress solver for Biot coupled with elasticity """ tic = time.time() # Data loading step # Linear solver starts here nd = gb.dim_max() g = gb.grids_of_dimension(nd)[0] data = gb.node_props(g) num_cells = g.num_cells # Get indices of different dofs # full_dof contains the number of dofs per block. To get a global ordering, use global_dof = np.r_[0, np.cumsum(full_dof)] # split global variable block_u = block_dof[(g, "u")] block_p = block_dof[(g, "p")] block_lam_u = block_dof[((g, g), "lam_u")] if ((g, g), "lam_p") in block_dof: block_lam_p = block_dof[((g, g), "lam_p")] mortar_p_ind = np.arange(global_dof[block_lam_p], global_dof[block_lam_p + 1]) else: # if we don't have a mortar variable for pressure (non-permeable fractures) mortar_p_ind = np.array([], dtype=np.int) # Get the global displacement and pressure dofs el_ind = np.arange(global_dof[block_u], global_dof[block_u + 1]) p_ind = np.arange(global_dof[block_p], global_dof[block_p + 1]) mortar_el_ind = np.arange(global_dof[block_lam_u], global_dof[block_lam_u + 1]) num_mortar = full_dof[-1] # merge pressure and pressure mortar indices p_full_ind = np.hstack((p_ind, mortar_p_ind)) rest_ind = np.hstack((el_ind, p_full_ind)) # Extract submatrices A_rest_rest = A[rest_ind][:, rest_ind] A_rest_m = A[rest_ind][:, mortar_el_ind] A_m_rest = A[mortar_el_ind][:, rest_ind] A_m_m = A[mortar_el_ind, :][:, mortar_el_ind] b_el = b[el_ind] n = num_cells * nd solution = np.zeros_like(b) residuals = [] def callback(r): residuals.append(r) # Preconditioning of the linear system, based on a Schur complement reduction to a # system in the elasticity variables. # Approximation of the inverse of A_m_m, by a diagonal matrix. # The quality of this for various configurations of the mortar variable is not clear. iA_m_m = sps.dia_matrix((1.0 / A_m_m.diagonal(), 0), A_m_m.shape) # Also create a factorization of the mortar variable. This is relatively cheap, so why not A_m_m_solve = sps.linalg.factorized(A_m_m) # Schur complement formulation, using the approximated inv(A_m_m) S = A_rest_rest - A_rest_m * iA_m_m * A_m_rest S_el = S[:, el_ind][el_ind, :] p_schur_ind = np.arange(el_ind.size, S.shape[0]) S_p = S[:, p_schur_ind][p_schur_ind] S_el_p = S[el_ind][:, p_schur_ind] S_p_el = S[p_schur_ind][:, el_ind] # Create an AMG hierarchy amg_args = { 'presmoother': ('gauss_seidel', { 'sweep': 'symmetric', 'iterations': 2 }), 'postsmoother': ('gauss_seidel', { 'sweep': 'symmetric', 'iterations': 2 }), } #ml = pyamg.smoothed_aggregation_solver(S_el, symmetry='nonsymmetric', **amg_args) ml = pyamg.rootnode_solver(S_el, symmetry='nonsymmetric', **amg_args) print(ml) # Use as preconditioner solve_el = ml.aspreconditioner(cycle='W') biot_alpha = data[pp.PARAMETERS]['mech']['biot_alpha'] rock_type = data[pp.PARAMETERS]['mech']['rock'] stab_size = p_schur_ind.size stab_vec = (biot_alpha**2 / (2 * (2 * rock_type.MU / nd + rock_type.LAMBDA)) * np.ones(stab_size)) stabilization = sps.dia_matrix((stab_vec, 0), shape=(stab_size, stab_size)) solve_p = sps.linalg.factorized(S_p + stabilization) def solve_fixed_stress(r): r_p = r[p_schur_ind] dp = solve_p(r_p) r_el = r[el_ind] - S_el_p * dp d_el = solve_el(r_el) return np.hstack((d_el, dp)) def precond_schur(r): # Mortar residual rm = r[mortar_el_ind] # Residual for the elasticity is the local one, plus the mapping of the mortar residual r_rest = r[rest_ind] - A_rest_m * A_m_m_solve(rm) # Solve, using specified solver du = solve_fixed_stress(r_rest) # Map back to mortar residual dm = A_m_m_solve(rm - A_m_rest * du) return np.hstack((du, dm)) max_it = 1000 M = sps.linalg.LinearOperator(A.shape, precond_schur) # Inital guess if x0 is None: x0 = np.zeros(A.shape[1]) solution, info = sps.linalg.gmres(A, b, M=M, x0=x0, restart=max_it, callback=callback, maxiter=max_it, tol=1e-11) if len(residuals) > 0: print("Linear solver residual: ", residuals[-1]) print("Linear solver iterations: ", len(residuals)) print('Linear solver time: ' + str(time.time() - tic)) return solution, info, residuals
from cvoutput import * from convergence_tools import print_cycle_history ## # Run Rotated Anisotropic Diffusion n = 10 nx = n ny = n stencil = diffusion_stencil_2d(type='FE',epsilon=0.001,theta=scipy.pi/3) A = stencil_grid(stencil, (nx,ny), format='csr') numpy.random.seed(625) x = scipy.rand(A.shape[0]) b = A*scipy.rand(A.shape[0]) ml = rootnode_solver(A, strength=('evolution', {'epsilon':2.0}), smooth=('energy', {'degree':2}), max_coarse=10) resvec = [] x = ml.solve(b, x0=x, maxiter=20, tol=1e-14, residuals=resvec) print_cycle_history(resvec, ml, verbose=True, plotting=False) ## # Write ConnectionViewer files for multilevel hierarchy ml xV,yV = numpy.meshgrid(numpy.arange(0,ny,dtype=float),numpy.arange(0,nx,dtype=float)) Verts = numpy.concatenate([[xV.ravel()],[yV.ravel()]],axis=0).T outputML("test", Verts, ml) print "\n\nOutput files for matrix stencil visualizations in ConnectionViewer are: \n \ test_A*.mat \n test_fine*.marks \n test_coarse*.marks \n \ test_R*.mat \n test_P*.mat \nwhere \'*\' is the level number" ##
# Illustrates the selection of aggregates in AMG based on smoothed aggregation import numpy from pyamg import rootnode_solver from pyamg.gallery import load_example data = load_example('unit_square') A = data['A'].tocsr() # 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 Root-Node Solver mls = rootnode_solver(A, max_levels=2, max_coarse=1, keep=True) # AggOp[i,j] is 1 iff node i belongs to aggregate j AggOp = mls.levels[0].AggOp # determine which edges lie entirely inside an aggregate # AggOp.indices[n] is the aggregate to which vertex n belongs inner_edges = AggOp.indices[E[:,0]] == AggOp.indices[E[:,1]] outer_edges = -inner_edges # Grab the root-nodes (i.e., the C/F splitting) Cpts = mls.levels[0].Cpts Fpts = mls.levels[0].Fpts from draw import lineplot from pylab import figure, axis, scatter, show, title ##
smooth=smooth, strength=("evolution", {"epsilon": evolution_theta, "k": 2}), ) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_ode[run] = (resvec[-1] / resvec[0]) ** (1.0 / len(resvec)) complexity_ode[run] = ml.operator_complexity() nnz_ode[run] = A.nnz sizelist_ode[run] = A.shape[0] # Evolution strength measure ml = rootnode_solver( A, max_coarse=mcoarse, coarse_solver="pinv2", presmoother=prepost, postsmoother=prepost, smooth=smooth, strength=("evolution", {"epsilon": evolution_theta, "k": 2}), ) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_ode_root[run] = (resvec[-1] / resvec[0]) ** (1.0 / len(resvec)) complexity_ode_root[run] = ml.operator_complexity() nnz_ode_root[run] = A.nnz sizelist_ode_root[run] = A.shape[0] run += 1 # Print Problem Description print "\nAMG Scalability Study for Ax = 0, x_init = rand\n"
print("Test convergence for a 200x200 Grid, Linearized Elasticity Problem") choice = input('\n Input Choice:\n' + '1: Run smoothed_aggregation_solver\n' + '2: Run rootnode_solver\n') # Create matrix and candidate vectors. B has 3 columns, representing # rigid body modes of the mesh. B[:,0] and B[:,1] are translations in # the X and Y directions while B[:,2] is a rotation. A, B = pyamg.gallery.linear_elasticity((200, 200), format='bsr') # Construct solver using AMG based on Smoothed Aggregation (SA) choice = int(choice) if choice == 1: ml = pyamg.smoothed_aggregation_solver(A, B=B, smooth='energy') elif choice == 2: ml = pyamg.rootnode_solver(A, B=B, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") # Display hierarchy information print(ml) # Create random right hand side b = np.random.rand(A.shape[0], 1) # Solve Ax=b residuals = [] x = ml.solve(b, tol=1e-10, residuals=residuals) print("Number of iterations: {}d\n".format(len(residuals))) # Output convergence
def get(self, k: int, heuristic: str, randomization: str, density: float = None, **kwargs) -> Subspace: """ Compute a subspace in two levels, a first one obtained via an algebraic multi-grid method, and the second one of random type. The resulting subspace is then in the form of a product. :param k: Number of approximate eigen-vectors to compute. :param heuristic: Name of the algebraic multi-grid heuristic used to construct the hierarchy. :param randomization: Name of the random distribution to use for the second level projection. :param density: If provided, the random operator is sparse with given density. :param kwargs: complementary arguments for algebraic multi-grid construction, see PyAMG library for details. """ # Setup multi-grid hierarchical structure with corresponding heuristic if heuristic == 'ruge_stuben': amg = pyamg.ruge_stuben_solver(self.linear_op.mat.tocsr(), max_levels=2, **kwargs) elif heuristic == 'smoothed_aggregated': amg = pyamg.smoothed_aggregation_solver(self.linear_op.mat.tocsr(), max_levels=2, **kwargs) elif heuristic == 'rootnode': amg = pyamg.rootnode_solver(self.linear_op.mat.tocsr(), max_levels=2, **kwargs) else: raise SubspaceError( 'Algebraic multi-grid heuristic {} unknown.'.format(heuristic)) self.P = Subspace(amg.levels[0].P) G = None _, k_ = self.P.shape if k > k_: warnings.warn( 'Random restriction size superior to coarse operator size, hence truncated.' ) k = k_ # Sanitize random distribution argument if randomization not in ['gaussian']: raise SubspaceError( 'Randomization name {} unknown.'.format(heuristic)) # Initialize subspace in dok format to allow easy update if randomization == 'gaussian': if density is not None: rvs = scipy.stats.norm().rvs G = Subspace( scipy.sparse.random(k_, k, density=density, data_rvs=rvs)) else: G = Subspace(numpy.random.randn(k_, k)) return self.P @ G
def solve(self, method, **kwargs): """Solves the linear system A x = b for the vector of unknown pressures x, either using a direct solver or an iterative AMG solver. From the pressures, the flow field is computed. INPUT: method: This can be either 'direct' or 'iterative' **kwargs precision: The accuracy to which the ls is to be solved. If not supplied, machine accuracy will be used. maxiter: The maximum number of iterations. The default value for the iterative solver is 250. OUTPUT: None - G is modified in place. """ b = self._b G = self._G htt2htd = self._P.tube_to_discharge_hematocrit A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, b) elif method == 'iterative': if kwargs.has_key('precision'): eps = kwargs['precision'] else: eps = self._eps if kwargs.has_key('maxiter'): maxiter = kwargs['maxiter'] else: maxiter = 250 AA = pyamg.smoothed_aggregation_solver(A, max_levels=10, max_coarse=500) x = abs(AA.solve(self._b, x0=None, tol=eps, accel='cg', cycle='V', maxiter=maxiter)) # abs required, as (small) negative pressures may arise elif method == 'iterative2': # Set linear solver ml = rootnode_solver(A, smooth=('energy', {'degree':2}), strength='evolution' ) M = ml.aspreconditioner(cycle='V') # Solve pressure system x,info = gmres(A, self._b, tol=self._eps, maxiter=50, M=M) if info != 0: print('ERROR in Solving the Matrix') G.vs['pressure'] = x self._x = x conductance = self._conductance G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - \ G.vs[edge.target]['pressure']) * \ conductance[i] for i, edge in enumerate(G.es)] for v in G.vs: v['pressure']=v['pressure']/vgm.units.scaling_factor_du('mmHg',G['defaultUnits']) if self._withRBC: for e in G.es: dischargeHt = min(htt2htd(e['htt'], e['diameter'], self._invivo), 1.0) e['v']=dischargeHt/e['htt']*e['flow']/(0.25*np.pi*e['diameter']**2) else: for e in G.es: e['v']=e['flow']/(0.25*np.pi*e['diameter']**2) #Convert 'pBC' from default Units to mmHg pBCneNone=G.vs(pBC_ne=None).indices if 'diamCalcEff' in G.es.attribute_names(): del(G.es['diamCalcEff']) if 'effResistance' in G.es.attribute_names(): del(G.es['effResistance']) if 'conductance' in G.es.attribute_names(): del(G.es['conductance']) if 'resistance' in G.es.attribute_names(): del(G.es['resistance']) G.vs[pBCneNone]['pBC']=np.array(G.vs[pBCneNone]['pBC'])*(1/vgm.units.scaling_factor_du('mmHg',G['defaultUnits'])) vgm.write_pkl(G, 'G_final.pkl') vgm.write_vtp(G, 'G_final.vtp',False) #Write Output sampledict={} for eprop in ['flow', 'v']: if not eprop in sampledict.keys(): sampledict[eprop] = [] sampledict[eprop].append(G.es[eprop]) for vprop in ['pressure']: if not vprop in sampledict.keys(): sampledict[vprop] = [] sampledict[vprop].append(G.vs[vprop]) g_output.write_pkl(sampledict, 'sampledict.pkl')
def update(self, thickness_edge, vc, c, g): self.thicknessInv[:] = 1. / thickness_edge ## Construct the blocks self.A11 = self.AC.multiply(self.thicknessInv) self.A11 *= self.mSkewgrad_td self.A12 = self.AMC.multiply(self.thicknessInv) self.A12 *= self.mGrad_n_n self.A12 += self.AC.multiply(self.thicknessInv) * self.GN self.A12 *= 0.5 self.A21 = self.AD.multiply(self.thicknessInv) self.A21 *= self.SN self.A21 += self.AMD.multiply(self.thicknessInv) * self.mSkewgrad_td self.A21 *= 0.5 self.A22 = self.AD.multiply(self.thicknessInv) self.A22 *= self.mGrad_n_n #self.A11 = self.A11.tolil( ) #self.A22 = self.A22.tolil( ) if c.on_a_global_sphere: self.A11[0, 0] = -2 * np.sqrt(3.) / thickness_edge[0] self.A22[0, 0] = -2 * np.sqrt(3.) / thickness_edge[0] else: self.A11[g.cellBoundary - 1, g.cellBoundary - 1] = -2 * np.sqrt(3.) / thickness_edge[0] self.A22[0, 0] = -2 * np.sqrt(3.) / thickness_edge[0] #self.A11 = self.A11.tocsr( ) #self.A22 = self.A22.tocsr( ) if c.linear_solver is 'lu': # Convert the matrices to CSC for better performance self.A11 = self.A11.tocsc() self.A22 = self.A22.tocsc() elif c.linear_solver is 'amg': self.A11 *= -1 self.A12 *= -1 self.A21 *= -1 self.A22 *= -1 B11 = np.ones((self.A11.shape[0], 1), dtype=self.A11.dtype) BH11 = B11.copy() self.A11_solver = rootnode_solver(self.A11, B=B11, BH=BH11, strength=('evolution', {'epsilon': 2.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 2, 'maxiter': 3}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") B22 = np.ones((self.A22.shape[0], 1), dtype=self.A22.dtype) BH22 = B22.copy() self.A22_solver = rootnode_solver(self.A22, B=B22, BH=BH22, strength=('evolution', {'epsilon': 2.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 2, 'maxiter': 3}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") elif c.linear_solver is 'amgx': self.d_A11.upload_CSR(self.A11) self.d_A22.upload_CSR(self.A22) self.slv11.setup(self.d_A11) self.slv22.setup(self.d_A22) else: raise ValueError("Invalid solver choice.")
# Illustrates the selection of aggregates in AMG based on smoothed aggregation import numpy from pyamg import rootnode_solver from pyamg.gallery import load_example data = load_example('unit_square') A = data['A'].tocsr() # 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 Root-Node Solver mls = rootnode_solver(A, max_levels=2, max_coarse=1, keep=True) # AggOp[i,j] is 1 iff node i belongs to aggregate j AggOp = mls.levels[0].AggOp # determine which edges lie entirely inside an aggregate # AggOp.indices[n] is the aggregate to which vertex n belongs inner_edges = AggOp.indices[E[:, 0]] == AggOp.indices[E[:, 1]] outer_edges = -inner_edges # Grab the root-nodes (i.e., the C/F splitting) Cpts = mls.levels[0].Cpts Fpts = mls.levels[0].Fpts from draw import lineplot from pylab import figure, axis, scatter, show, title ##
def __init__(self, A, linear_solver, env): if linear_solver is 'lu': self.A = A.tocsc() self.lu = splu(self.A) elif linear_solver is 'cg': self.A = A.tocsr() elif linear_solver in ['cudaCG']: self.A = A.tocsr() self.dData = env.cuda.to_device(self.A.data) self.dPtr = env.cuda.to_device(self.A.indptr) self.dInd = env.cuda.to_device(self.A.indices) self.cuSparseDescr = env.cuSparse.matdescr() elif linear_solver in ['cudaPCG']: self.A = A.tocsr() self.Adescr = env.cuSparse.matdescr() self.Adata = env.cuda.to_device(self.A.data) self.Aptr = env.cuda.to_device(self.A.indptr) self.Aind = env.cuda.to_device(self.A.indices) A_t = self.A.copy() A_t = -A_t # Make it positive definite A_t.data = np.where(A_t.nonzero()[0] >= A_t.nonzero()[1], A_t.data, 0.) A_t.eliminate_zeros() A_t_descr = env.cuSparse.matdescr(matrixtype='S', fillmode='L') info = env.cuSparse.csrsv_analysis(trans='N', m=A_t.shape[0], nnz=A_t.nnz, \ descr=A_t_descr, csrVal=A_t.data, \ csrRowPtr=A_t.indptr, csrColInd=A_t.indices) env.cuSparse.csric0(trans='N', m=A_t.shape[0], \ descr=A_t_descr, csrValM=A_t.data, csrRowPtrA=A_t.indptr,\ csrColIndA=A_t.indices, info=info) self.L = A_t self.Lmv_descr = env.cuSparse.matdescr() # self.Lsv_descr = cuSparse.matdescr(matrixtype='T', fillmode='L') self.Lsv_descr = env.cuSparse.matdescr(matrixtype='T') self.Ldata = env.cuda.to_device(self.L.data) self.Lptr = env.cuda.to_device(self.L.indptr) self.Lind = env.cuda.to_device(self.L.indices) self.Lsv_info = env.cuSparse.csrsv_analysis(trans='N', m=self.L.shape[0], \ nnz=self.L.nnz, descr=self.Lsv_descr, csrVal=self.Ldata, \ csrRowPtr=self.Lptr, csrColInd=self.Lind) self.LT = self.L.transpose() self.LT.tocsr() self.LTmv_descr = env.cuSparse.matdescr() # self.LTsv_descr = env.cuSparse.matdescr(matrixtype='T', fillmode='U') self.LTsv_descr = env.cuSparse.matdescr() self.LTdata = env.cuda.to_device(self.LT.data) self.LTptr = env.cuda.to_device(self.LT.indptr) self.LTind = env.cuda.to_device(self.LT.indices) self.LTsv_info = env.cuSparse.csrsv_analysis(trans='T', m=self.L.shape[0], \ nnz=self.L.nnz, descr=self.Lsv_descr, csrVal=self.Ldata, \ csrRowPtr=self.Lptr, csrColInd=self.Lind) elif linear_solver is 'pcg': self.A = A.tocsr() A_t = -self.D2s elif linear_solver is 'amg': self.A = A.tocsr() self.A_spd = self.A.copy() self.A_spd = -self.A_spd self.B = np.ones((self.A_spd.shape[0], 1), dtype=self.A_spd.dtype) self.BH = self.B.copy() if self.A_spd.shape[0] in [40962, 163842, 655362]: self.A_amg = rootnode_solver(self.A_spd, B=self.B, BH=self.BH, strength=('evolution', {'epsilon': 2.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 2, 'maxiter': 3}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") elif self.A_spd.shape[0] in [81920, 327680, 1310720, 5242880]: self.A_amg = rootnode_solver(self.A_spd, B=self.B, BH=self.BH, strength=('evolution', {'epsilon': 4.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 2, 'maxiter': 3}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") elif self.A_spd.shape[0] in [2621442]: self.A_amg = rootnode_solver(self.A_spd, B=self.B, BH=self.BH, strength=('evolution', {'epsilon': 4.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 3, 'maxiter': 4}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") else: print("Unknown matrix. Using a generic AMG solver") self.A_amg = rootnode_solver(self.A_spd, B=self.B, BH=self.BH, strength=('evolution', {'epsilon': 2.0, 'k': 2, 'proj_type': 'l2'}), smooth=('energy', {'weighting': 'local', 'krylov': 'cg', 'degree': 2, 'maxiter': 3}), improve_candidates=[('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), \ None, None, None, None, None, None, None, None, None, None, \ None, None, None, None], aggregate="standard", presmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), postsmoother=('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 1}), max_levels=15, max_coarse=300, coarse_solver="pinv") elif linear_solver is 'amgx': import pyamgx pyamgx.initialize() hA = A.tocsr() if hA.nnz * 1. / hA.shape[0] > 5.5: # Primary mesh AMGX_CONFIG_FILE_NAME = 'amgx_config/PCGF_CLASSICAL_AGGRESSIVE_PMIS_JACOBI.json' if hA.nnz * 1. / hA.shape[0] < 5.5: # Dual mesh AMGX_CONFIG_FILE_NAME = 'amgx_config/PCGF_CLASSICAL_AGGRESSIVE_PMIS.json' else: print( 'Error: cannot determine primary or dual mesh, not sure which config to use.' ) cfg = pyamgx.Config().create_from_file(AMGX_CONFIG_FILE_NAME) rsc = pyamgx.Resources().create_simple(cfg) mode = 'dDDI' # Create solver: self.amgx = pyamgx.Solver().create(rsc, cfg, mode) # Create matrices and vectors: d_A = pyamgx.Matrix().create(rsc, mode) self.d_x = pyamgx.Vector().create(rsc, mode) self.d_b = pyamgx.Vector().create(rsc, mode) d_A.upload(hA.indptr, hA.indices, hA.data) # Setup and solve system: self.amgx.setup(d_A) ## Clean up: #A.destroy() #x.destroy() #b.destroy() #self.amgx.destroy() #rsc.destroy() #cfg.destroy() #pyamgx.finalize() else: raise ValueError("Invalid solver choice.")
'epsilon': evolution_theta, 'k': 2 })) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_ode[run] = (resvec[-1] / resvec[0])**(1.0 / len(resvec)) complexity_ode[run] = ml.operator_complexity() nnz_ode[run] = A.nnz sizelist_ode[run] = A.shape[0] # Evolution strength measure ml = rootnode_solver(A, max_coarse=mcoarse, coarse_solver='pinv2', presmoother=prepost, postsmoother=prepost, smooth=smooth, strength=('evolution', { 'epsilon': evolution_theta, 'k': 2 })) resvec = [] x = ml.solve(b, x0=x0, maxiter=100, tol=1e-8, residuals=resvec) factors_ode_root[run] = (resvec[-1] / resvec[0])**(1.0 / len(resvec)) complexity_ode_root[run] = ml.operator_complexity() nnz_ode_root[run] = A.nnz sizelist_ode_root[run] = A.shape[0] run += 1 # Print Problem Description print "\nAMG Scalability Study for Ax = 0, x_init = rand\n"
space = LagrangeFiniteElementSpace(mesh, p=p) bc0 = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary) bc1 = NeumannBC(space, pde.neumann, threshold=pde.is_neumann_boundary) uh = space.function(dim=2) # (gdof, 2) and vector fem function uh[i, j] A = space.linear_elasticity_matrix(pde.mu, pde.lam) # (2*gdof, 2*gdof) F = space.source_vector(pde.source, dim=2) F = bc1.apply(F) A, F = bc0.apply(A, F, uh) if False: uh.T.flat[:] = spsolve(A, F) # (2, gdof ).flat else: ml = pyamg.rootnode_solver(A) # AMG solver M = ml.aspreconditioner(cycle='V') # preconditioner start = timer() uh.T.flat[:], info = cg(A, F, tol=1e-8, maxiter=100, M=M) # solve with CG end = timer() print('time:', end - start) # 原始的网格 mesh.add_plot(plt) # 变形的网格 mesh.node += scale * uh mesh.add_plot(plt) plt.show()
print "Test convergence for a simple 200x200 Grid, Linearized Elasticity Problem" choice = input('\n Input Choice:\n' + \ '1: Run smoothed_aggregation_solver\n' + \ '2: Run rootnode_solver\n' ) # Create matrix and candidate vectors. B has 3 columns, representing # rigid body modes of the mesh. B[:,0] and B[:,1] are translations in # the X and Y directions while B[:,2] is a rotation. A,B = linear_elasticity((200,200), format='bsr') # Construct solver using AMG based on Smoothed Aggregation (SA) if choice == 1: mls = smoothed_aggregation_solver(A, B=B, smooth='energy') elif choice == 2: mls = rootnode_solver(A, B=B, smooth='energy') else: raise ValueError("Enter a choice of 1 or 2") # Display hierarchy information print mls # Create random right hand side b = scipy.rand(A.shape[0],1) # Solve Ax=b residuals = [] x = mls.solve(b, tol=1e-10, residuals=residuals) print "Number of iterations: %d\n"%len(residuals) # Output convergence
def test_size(size, test_config): baseline_errors_div_diff = [] operator_complexities = [] fp_threshold = test_config.fp_threshold strength = test_config.strength presmoother = test_config.presmoother postsmoother = test_config.postsmoother coarse_solver = test_config.coarse_solver cycle = test_config.cycle splitting = test_config.splitting num_runs = test_config.num_runs dist = test_config.dist max_levels = test_config.max_levels iterations = test_config.iterations load_data = test_config.load_data block_periodic = False root_num_blocks = 1 if load_data: if dist == 'lognormal_laplacian_periodic': As = np.load( f"test_data_dir/delaunay_periodic_logn_num_As_{100}_num_points_{size}.npy" ) elif dist == 'lognormal_complex_fem': As = np.load( f"test_data_dir/fe_hole_logn_num_As_{100}_num_points_{size}.npy" ) else: raise NotImplementedError() for i in tqdm(range(num_runs)): if load_data: A = As[i] else: A = generate_A(size, dist, block_periodic, root_num_blocks) num_unknowns = A.shape[0] x0 = np.random.normal(loc=0.0, scale=1.0, size=num_unknowns) b = np.zeros((A.shape[0])) baseline_residuals = [] if splitting is 'CR' or splitting[0] is 'CR': baseline_solver = cr_solver(A, presmoother=presmoother, postsmoother=postsmoother, keep=True, max_levels=max_levels, CF=splitting, coarse_solver=coarse_solver) elif splitting is 'SA': baseline_solver = smoothed_aggregation_solver( A, strength=strength, presmoother=presmoother, postsmoother=postsmoother, max_levels=max_levels, keep=True, coarse_solver=coarse_solver) elif splitting is 'rootnode': baseline_solver = rootnode_solver(A, strength=strength, presmoother=presmoother, postsmoother=postsmoother, max_levels=max_levels, keep=True, coarse_solver=coarse_solver) else: baseline_solver = ruge_stuben_solver(A, strength=strength, interpolation='direct', presmoother=presmoother, postsmoother=postsmoother, keep=True, max_levels=max_levels, CF=splitting, coarse_solver=coarse_solver) operator_complexities.append(baseline_solver.operator_complexity()) _ = baseline_solver.solve(b, x0=x0, tol=0.0, maxiter=iterations, cycle=cycle, residuals=baseline_residuals) baseline_residuals = np.array(baseline_residuals) baseline_residuals = baseline_residuals[ baseline_residuals > fp_threshold] baseline_factor = baseline_residuals[-1] / baseline_residuals[-2] baseline_errors_div_diff.append(baseline_factor) baseline_errors_div_diff = np.array(baseline_errors_div_diff) baseline_errors_div_diff_mean = np.mean(baseline_errors_div_diff) baseline_errors_div_diff_std = np.std(baseline_errors_div_diff) operator_complexity_mean = np.mean(operator_complexities) operator_complexity_std = np.std(operator_complexities) if type(splitting) == tuple: splitting_str = splitting[0] + '_' + '_'.join( [f'{key}_{value}' for key, value in splitting[1].items()]) else: splitting_str = splitting results_file = open( f"results/baseline/{dist}_{num_unknowns}_cycle_{cycle}_max_levels_{max_levels}_split_{splitting_str}_results.txt", 'w') print(f"cycle: {cycle}, max levels: {max_levels}", file=results_file) print( f"asymptotic error factor baseline: {baseline_errors_div_diff_mean:.4f} ± {baseline_errors_div_diff_std:.5f}", file=results_file) print(f"num unknowns: {num_unknowns}") print( f"asymptotic error factor baseline: {baseline_errors_div_diff_mean:.4f} ± {baseline_errors_div_diff_std:.5f}" ) print( f"operator complexity: {operator_complexity_mean:.4f} ± {operator_complexity_std:.5f}" ) print( f"operator complexity: {operator_complexity_mean:.4f} ± {operator_complexity_std:.5f}", file=results_file) results_file.close()