def direct_solve(A, b, W, which='umfpack'): '''inv(A)*b''' print 'Solving system of size %d' % A.size(0) # NOTE: umfpack sometimes blows up, MUMPS produces crap more often than not if isinstance(W, list): wh = ii_Function(W) LUSolver(which).solve(A, wh.vector(), b) print('|b-Ax| from direct solver', (A * wh.vector() - b).norm('linf')) return wh wh = Function(W) LUSolver(which).solve(A, wh.vector(), b) print('|b-Ax| from direct solver', (A * wh.vector() - b).norm('linf')) if isinstance( W.ufl_element(), (ufl.VectorElement, ufl.TensorElement)) or W.num_sub_spaces() == 1: return ii_Function([W], [wh]) # Now get components Wblock = serialize_mixed_space(W) wh = wh.split(deepcopy=True) return ii_Function(Wblock, wh)
def __init__(self, *args, **kwargs): """ Create solver for :py:class:`SemiDecoupled <muflon.functions.discretization.SemiDecoupled>` discretization scheme. See :py:class:`Solver <muflon.solving.solvers.Solver>` for the list of valid initialization arguments. """ super(SemiDecoupled, self).__init__(*args, **kwargs) # Extract solution functions DS = self.data["model"].discretization_scheme() w_ch, w_ns = DS.solution_ctl() # Adjust bcs bcs_ch = [] bcs_ns = [] _bcs = self.data["model"].bcs() for bc_v in _bcs.get("v", []): assert isinstance(bc_v, tuple) assert len(bc_v) == len(w_ns.sub(0)) bcs_ns += [bc for bc in bc_v if bc is not None] bcs_ns += [bc for bc in _bcs.get("p", [])] # FIXME: Deal with possible bcs for ``phi`` and ``th`` # Prepare solver for CH part F = self.data["forms"]["nln"] J = derivative(F, w_ch) # Store solvers and collect other data self.data["problem_ch"] = self.CHProblem(F, bcs_ch, J) self.data["solver"] = OrderedDict() self.data["solver"]["CH"] = OrderedDict() self.data["solver"]["CH"]["lin"] = LUSolver("mumps") # NOTE: Initialization of nonlinear solver is postponed until setup self.data["solver"]["NS"] = LUSolver("mumps") self.data["sol_ch"] = w_ch self.data["sol_ns"] = w_ns self.data["bcs_ns"] = bcs_ns # Preparation for tackling singular systems if self._flags["fix_p"]: null_space, null_fcn = DS.build_pressure_null_space() self.data["null_space"] = null_space self.data["null_fcn"] = null_fcn # Store number of iterations self.iters = OrderedDict() self.iters["CH"] = [0, 0] # (total, last solve) self.iters["NS"] = [0, 0] # (total, last solve)
def solve_alpha_M_beta_F(self, alpha, beta, b, t): """Solve :code:`alpha * M * u + beta * F(u, t) = b` with Dirichlet conditions. """ matrix = alpha * self.M + beta * self.A # See above for float conversion right_hand_side = -float(beta) * self.b.copy() if b: right_hand_side += b for bc in self.dirichlet_bcs: bc.apply(matrix, right_hand_side) # TODO proper preconditioner for convection if self.convection: # Use HYPRE-Euclid instead of ILU for parallel computation. # However, this PC sometimes fails. # solver = KrylovSolver('gmres', 'hypre_euclid') # Fallback: solver = LUSolver() else: solver = KrylovSolver("gmres", "hypre_amg") solver.parameters["relative_tolerance"] = 1.0e-13 solver.parameters["absolute_tolerance"] = 0.0 solver.parameters["maximum_iterations"] = 100 solver.parameters["monitor_convergence"] = True solver.set_operator(matrix) u = Function(self.Q) solver.solve(u.vector(), right_hand_side) return u
def assert_solves( mesh: Mesh, diffusion: Coefficient, convection: Optional[Coefficient], reaction: Optional[Coefficient], source: Coefficient, exact: Coefficient, l2_tol: Optional[float] = 1.0e-8, h1_tol: Optional[float] = 1.0e-6, ): eafe_matrix = eafe_assemble(mesh, diffusion, convection, reaction) pw_linears = FunctionSpace(mesh, "Lagrange", 1) test_function = TestFunction(pw_linears) rhs_vector = assemble(source * test_function * dx) bc = DirichletBC(pw_linears, exact, lambda _, on_bndry: on_bndry) bc.apply(eafe_matrix, rhs_vector) solution = Function(pw_linears) solver = LUSolver(eafe_matrix, "default") solver.parameters["symmetric"] = False solver.solve(solution.vector(), rhs_vector) l2_err: float = errornorm(exact, solution, "l2", 3) assert l2_err <= l2_tol, f"L2 error too large: {l2_err} > {l2_tol}" h1_err: float = errornorm(exact, solution, "H1", 3) assert h1_err <= h1_tol, f"H1 error too large: {h1_err} > {h1_tol}"
def _get_constant_pressure(self, W): w = TrialFunction(W) w_ = TestFunction(W) p_ = self.test_functions()["p"] A, b = assemble_system(inner(w, w_) * dx, p_ * dx) null_fcn = Function(W) solver = LUSolver("mumps") solver.solve(A, null_fcn.vector(), b) return null_fcn
def __init__(self, *args, **kwargs): """ Create linear solver for :py:class:`FullyDecoupled \ <muflon.functions.discretization.FullyDecoupled>` discretization scheme. See :py:class:`Solver <muflon.solving.solvers.Solver>` for the list of valid initialization arguments. """ super(FullyDecoupled, self).__init__(*args, **kwargs) # Create solvers solver = OrderedDict() solver["phi"] = LUSolver("mumps") solver["chi"] = LUSolver("mumps") solver["v"] = LUSolver("mumps") solver["p"] = LUSolver("mumps") self.data["solver"] = solver # Initialize flags self._flags["setup"] = False
def _assemble(self): # Get input: self.gamma = self.Parameters['gamma'] if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta'] else: self.beta = 0.0 self.Vm = self.Parameters['Vm'] if self.Parameters.has_key('m0'): self.m0 = self.Parameters['m0'].copy(deepcopy=True) isFunction(self.m0) else: self.m0 = Function(self.Vm) self.mtrial = TrialFunction(self.Vm) self.mtest = TestFunction(self.Vm) self.mysample = Function(self.Vm) self.draw = Function(self.Vm) # Assemble: self.R = assemble(inner(nabla_grad(self.mtrial), \ nabla_grad(self.mtest))*dx) self.M = PETScMatrix() assemble(inner(self.mtrial, self.mtest) * dx, tensor=self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-16: self.precond = self.gamma * self.R + self.beta * self.M else: self.precond = self.gamma * self.R + (1e-14) * self.M # Discrete operator K: self.K = self.gamma * self.R + self.beta * self.M # Get eigenvalues for M: self.eigsolM = SLEPcEigenSolver(self.M) self.eigsolM.solve() # Solver for M^{-1}: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.M) # Solver for K^{-1}: self.solverK = LUSolver() self.solverK.parameters['reuse_factorization'] = True self.solverK.parameters['symmetric'] = True self.solverK.set_operator(self.K)
def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test * trial * dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim())
def solve_alpha_M_beta_F(self, alpha, beta, b, t): '''Solve alpha * M * u + beta * F(u, t) = b for u. ''' A = alpha * self.M + beta * self.A # See above for float conversion right_hand_side = - float(beta) * self.b.copy() if b: right_hand_side += b for bc in self.bcs: bc.apply(A, b) # The Krylov solver doesn't converge solver = LUSolver() solver.set_operator(A) u = Function(self.V) solver.solve(u.vector(), b) return u
def main(module_name, ncases, params, petsc_params): ''' Run the test case in module with ncases. Optionally store results in savedir. For some modules there are multiple (which) choices of preconditioners. ''' # Unpack for k, v in params.items(): exec(k + '=v', locals()) RED = '\033[1;37;31m%s\033[0m' print RED % ('\tRunning %s' % module_name) module = __import__(module_name) # no importlib in python2.7 # Setup the MMS case u_true, rhs_data = module.setup_mms(eps) # Setup the convergence monitor if log: params = [('solver', solver), ('precond', str(precond)), ('eps', str(eps))] path = '_'.join([module_name] + ['%s=%s' % pv for pv in params]) path = os.path.join(save_dir if save_dir else '.', path) path = '.'.join([path, 'txt']) else: path = '' memory, residuals = [], [] monitor = module.setup_error_monitor(u_true, memory, path=path) # Sometimes it is usedful to transform the solution before computing # the error. e.g. consider subdomains if hasattr(module, 'setup_transform'): # NOTE: transform take two args for case and the current computed # solution transform = module.setup_transform else: transform = lambda i, x: x print '=' * 79 print '\t\t\tProblem eps = %g' % eps print '=' * 79 for i in ncases: a, L, W = module.setup_problem(i, rhs_data, eps=eps) # Assemble blocks t = Timer('assembly') t.start() AA, bb = map(ii_assemble, (a, L)) print '\tAssembled blocks in %g s' % t.stop() wh = ii_Function(W) if solver == 'direct': # Turn into a (monolithic) PETScMatrix/Vector t = Timer('conversion') t.start() AAm, bbm = map(ii_convert, (AA, bb)) print '\tConversion to PETScMatrix/Vector took %g s' % t.stop() t = Timer('solve') t.start() LUSolver('umfpack').solve(AAm, wh.vector(), bbm) print '\tSolver took %g s' % t.stop() niters = 1 else: # Here we define a Krylov solver using PETSc BB = module.setup_preconditioner(W, precond, eps=eps) ## AA and BB as block_mat ksp = PETSc.KSP().create() # Default is minres if '-ksp_type' not in petsc_params: petsc_params['-ksp_type'] = 'minres' opts = PETSc.Options() for key, value in petsc_params.iteritems(): opts.setValue(key, None if value == 'none' else value) ksp.setOperators(ii_PETScOperator(AA)) ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED) # ksp.setTolerances(rtol=1E-6, atol=None, divtol=None, max_it=300) ksp.setConvergenceHistory() # We attach the wrapped preconditioner defined by the module ksp.setPC(ii_PETScPreconditioner(BB, ksp)) ksp.setFromOptions() print ksp.getTolerances() # Want the iterations to start from random wh.block_vec().randomize() # Solve, note the past object must be PETSc.Vec t = Timer('solve') t.start() ksp.solve(as_petsc_nest(bb), wh.petsc_vec()) print '\tSolver took %g s' % t.stop() niters = ksp.getIterationNumber() residuals.append(ksp.getConvergenceHistory()) # Let's check the final size of the residual r_norm = (bb - AA * wh.block_vec()).norm() # Convergence? monitor.send((transform(i, wh), niters, r_norm)) # Only send the final if save_dir: path = os.path.join(save_dir, module_name) for i, wh_i in enumerate(wh): # Renaming to make it easier to save state in Visit/Pareview wh_i.rename('u', str(i)) File('%s_%d.pvd' % (path, i)) << wh_i # Plot relative residual norm if plot: plt.figure() [ plt.semilogy(res / res[0], label=str(i)) for i, res in enumerate(residuals, 1) ] plt.legend(loc='best') plt.show()