def __init__(self, v, v_out, bcs=None, solver_parameters=None, constant_jacobian=True): if isinstance(v, expression.Expression) or \ not isinstance(v, (ufl.core.expr.Expr, function.Function)): raise ValueError("Can only project UFL expression or Functions not '%s'" % type(v)) self._same_fspace = (isinstance(v, function.Function) and v.function_space() == v_out.function_space()) self.v = v self.v_out = v_out self.bcs = bcs if not self._same_fspace or self.bcs: V = v_out.function_space() p = ufl_expr.TestFunction(V) q = ufl_expr.TrialFunction(V) a = ufl.inner(p, q)*ufl.dx L = ufl.inner(p, v)*ufl.dx problem = vs.LinearVariationalProblem(a, L, v_out, bcs=self.bcs, constant_jacobian=constant_jacobian) if solver_parameters is None: solver_parameters = {} solver_parameters.setdefault("ksp_type", "cg") self.solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_parameters)
def _solve_varproblem(*args, **kwargs): "Solve variational problem a == L or F == 0" # Extract arguments eq, u, bcs, J, Jp, M, form_compiler_parameters, \ solver_parameters, nullspace, nullspace_T, \ near_nullspace, \ options_prefix = _extract_args(*args, **kwargs) appctx = kwargs.get("appctx", {}) # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = vs.LinearVariationalProblem( eq.lhs, eq.rhs, u, bcs, Jp, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = vs.LinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, near_nullspace=near_nullspace, options_prefix=options_prefix, appctx=appctx) solver.solve() # Solve nonlinear variational problem else: if eq.rhs != 0: raise TypeError( "Only '0' support on RHS of nonlinear Equation, not %r" % eq.rhs) # Create problem problem = vs.NonlinearVariationalProblem( eq.lhs, u, bcs, J, Jp, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = vs.NonlinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, near_nullspace=near_nullspace, options_prefix=options_prefix, appctx=appctx) solver.solve()
def _solve_varproblem(*args, **kwargs): "Solve variational problem a == L or F == 0" # Extract arguments eq, u, bcs, J, Jp, M, form_compiler_parameters, \ solver_parameters, nullspace, options_prefix, \ nest = _extract_args(*args, **kwargs) # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = vs.LinearVariationalProblem( eq.lhs, eq.rhs, u, bcs, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.LinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, options_prefix=options_prefix) with progress(INFO, 'Solving linear variational problem'): solver.solve() # Solve nonlinear variational problem else: if eq.rhs != 0: raise TypeError( "Only '0' support on RHS of nonlinear Equation, not %r" % eq.rhs) # Create problem problem = vs.NonlinearVariationalProblem( eq.lhs, u, bcs, J, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.NonlinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, options_prefix=options_prefix) with progress(INFO, 'Solving nonlinear variational problem'): solver.solve()
def pml(mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=None, solver_parameters=None, inner_region=None, fspace=None, tfspace=None, true_sol_grad=None, pml_type=None, delta=None, quad_const=None, speed=None, pml_min=None, pml_max=None): """ For unlisted arg descriptions, see run_method :arg inner_region: boundary id of non-pml region :arg pml_type: Type of pml function, either 'quadratic' or 'bdy_integral' :arg delta: For :arg:`pml_type` of 'bdy_integral', added to denominator to prevent 1 / 0 at edge of boundary :arg quad_const: For :arg:`pml_type` of 'quadratic', a scaling constant :arg speed: Speed of sound :arg pml_min: A list, *pml_min[i]* is where to begin pml layer in direction *i* :arg pml_max: A list, *pml_max[i]* is where to end pml layer in direction *i* """ # Handle defauls if pml_type is None: pml_type = 'bdy_integral' if delta is None: delta = 1e-3 if quad_const is None: quad_const = 1.0 if speed is None: speed = 340.0 pml_types = ['bdy_integral', 'quadratic'] if pml_type not in pml_types: raise ValueError("PML type of %s is not one of %s" % (pml_type, pml_types)) xx = SpatialCoordinate(mesh) # {{{ create sigma functions for PML sigma = None if pml_type == 'bdy_integral': sigma = [ Constant(speed) / (Constant(delta + extent) - abs(coord)) for extent, coord in zip(pml_max, xx) ] elif pml_type == 'quadratic': sigma = [ Constant(quad_const) * (abs(coord) - Constant(min_))**2 for min_, coord in zip(pml_min, xx) ] r""" Here \kappa is the wave number and c is the speed ..math:: \kappa = \frac{ \omega } { c } """ omega = wave_number * speed # {{{ Set up PML functions gamma = [ Constant(1.0) + conditional( abs(real(coord)) >= real(min_), Constant(1j / omega) * sigma_i, Constant(0.0)) for min_, coord, sigma_i in zip(pml_min, xx, sigma) ] kappa = [None] * len(gamma) gamma_prod = 1.0 for i in range(len(gamma)): gamma_prod *= gamma[i] tensor_i = [Constant(0.0) for _ in range(len(gamma))] tensor_i[i] = 1.0 r""" *i*th entry is .. math:: \frac{\prod_{j\neq i} \gamma_j}{ \gamma_i } """ for j in range(len(gamma)): if j != i: tensor_i[i] *= gamma[j] else: tensor_i[i] /= gamma[j] kappa[i] = tensor_i kappa = as_tensor(kappa) # }}} p = TrialFunction(fspace) q = TestFunction(fspace) k = wave_number # Just easier to look at a = (inner(dot(grad(p), kappa), grad(q)) - Constant(k**2) * gamma_prod * inner(p, q)) * dx n = FacetNormal(mesh) L = inner(dot(true_sol_grad, n), q) * ds(scatterer_bdy_id) bc = DirichletBC(fspace, Constant(0), outer_bdy_id) solution = Function(fspace) #solve(a == L, solution, bcs=[bc], options_prefix=options_prefix) # Create a solver and return the KSP object with the solution so that can get # PETSc information # Create problem problem = vs.LinearVariationalProblem(a, L, solution, [bc], None) # Create solver and call solve solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_parameters, options_prefix=options_prefix) solver.solve() return solver.snes, solution
def transmission( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=None, solver_parameters=None, fspace=None, true_sol_grad_expr=None, ): r""" preconditioner_gamma and preconditioner_lambda are used to precondition with the following equation: \Delta u - \kappa^2 \gamma u = 0 (\partial_n - i\kappa\beta) u |_\Sigma = 0 """ # need as tuple so can use integral measure if isinstance(outer_bdy_id, int): outer_bdy_id = [outer_bdy_id] outer_bdy_id = tuple(outer_bdy_id) u = TrialFunction(fspace) v = TestFunction(fspace) a = inner(grad(u), grad(v)) * dx - Constant(wave_number**2) * inner(u, v) * dx \ - Constant(1j * wave_number) * inner(u, v) * ds(outer_bdy_id) n = FacetNormal(mesh) metadata = {'quadrature_degree': 2 * fspace.ufl_element().degree()} L = inner(inner(true_sol_grad_expr, n), v) * ds(scatterer_bdy_id, metadata=metadata) solution = Function(fspace) # {{{ Used for preconditioning if 'gamma' in solver_parameters or 'beta' in solver_parameters: solver_params = dict(solver_parameters) gamma = complex(solver_parameters.pop('gamma', 1.0)) import cmath beta = complex(solver_parameters.pop('beta', cmath.sqrt(gamma))) aP = inner(grad(u), grad(v)) * dx \ - Constant(wave_number**2 * gamma) * inner(u, v) * dx \ - Constant(1j * wave_number * beta) * inner(u, v) * ds(outer_bdy_id) else: aP = None solver_params = solver_parameters # }}} # prepare to set up pyamg preconditioner if using it using_pyamg = solver_params['pc_type'] == 'pyamg' if using_pyamg: pyamg_tol = solver_parameters.get('pyamg_tol', None) if pyamg_tol is not None: pyamg_tol = float(pyamg_tol) pyamg_maxiter = solver_params.get('pyamg_maxiter', None) if pyamg_maxiter is not None: pyamg_maxiter = int(pyamg_maxiter) del solver_params['pc_type'] # Create a solver and return the KSP object with the solution so that can get # PETSc information # Create problem problem = vs.LinearVariationalProblem(a, L, solution, aP=aP) # Create solver and call solve solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_params, options_prefix=options_prefix) # prepare to set up pyamg preconditioner if using it if using_pyamg: A = assemble(a).M.handle pc = solver.snes.getKSP().pc pc.setType(pc.Type.PYTHON) pc.setPythonContext( AMGTransmissionPreconditioner(wave_number, fspace, A, tol=pyamg_tol, maxiter=pyamg_maxiter, use_plane_waves=True)) # If using pyamg as preconditioner, use it! try: solver.solve() except ConvergenceError: pass return solver.snes, solution
solution = Function(fspace) # Create a solver and return the KSP object with the solution so that can get # PETSc information # Create problem problem = vs.LinearVariationalProblem(a, L, solution) # Create solver pyamg_tol = None pyamg_maxiter = None solver_params = { 'pyamg_tol': pyamg_tol, 'pyamg_maxiter': pyamg_maxiter, 'ksp_monitor': None, } solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_params) # Build matrix and store text file A = assemble(a).M.handle store_mat = True if store_mat: dim = mesh.geometric_dimension() file_name = f"matrix_txt_files/helmholtz-{dim}D-h{h}.txt" from firedrake.petsc import PETSc myviewer = PETSc.Viewer().createASCII( file_name, mode=PETSc.Viewer.Format.ASCII_COMMON, comm=PETSc.COMM_WORLD) A.view(myviewer) # set up pyamg preconditioner and solve