def coarsen_nlvp(problem, coefficient_mapping=None): # Build set of coefficients we need to coarsen seen = set() coefficients = problem.F.coefficients() + problem.J.coefficients() if problem.Jp is not None: coefficients = coefficients + problem.Jp.coefficients() # Coarsen them, and remember where from. if coefficient_mapping is None: coefficient_mapping = {} for c in coefficients: if c not in seen: coefficient_mapping[c] = coarsen( c, coefficient_mapping=coefficient_mapping) seen.add(c) u = coefficient_mapping[problem.u] bcs = [coarsen(bc) for bc in problem.bcs] J = coarsen(problem.J, coefficient_mapping=coefficient_mapping) Jp = coarsen(problem.Jp, coefficient_mapping=coefficient_mapping) F = coarsen(problem.F, coefficient_mapping=coefficient_mapping) problem = firedrake.NonlinearVariationalProblem( F, u, bcs=bcs, J=J, Jp=Jp, form_compiler_parameters=problem.form_compiler_parameters) return problem
def initial_values(sim): print("Solving steady heat driven cavity to obtain initial values") Ra = 2.518084e6 Pr = 6.99 sim.grashof_number = sim.grashof_number.assign(Ra / Pr) sim.prandtl_number = sim.prandtl_number.assign(Pr) dim = sim.mesh.geometric_dimension() T_c = sim.cold_wall_temperature.__float__() w = fe.interpolate( fe.Expression((0., ) + (0., ) * dim + (T_c, ), element=sim.element), sim.function_space) F = heat_driven_cavity_variational_form_residual( sim=sim, solution=w) * fe.dx(degree=sim.quadrature_degree) T_h = sim.hot_wall_temperature.__float__() problem = fe.NonlinearVariationalProblem( F=F, u=w, bcs=dirichlet_boundary_conditions(sim), J=fe.derivative(F, w)) solver = fe.NonlinearVariationalSolver(problem=problem, solver_parameters={ "snes_type": "newtonls", "snes_monitor": True, "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "pc_factor_mat_solver_type": "mumps" }) def solve(): solver.solve() return w w, _ = \ sapphire.continuation.solve_with_bounded_regularization_sequence( solve = solve, solution = w, backup_solution = fe.Function(w), regularization_parameter = sim.grashof_number, initial_regularization_sequence = ( 0., sim.grashof_number.__float__())) return w
def temperature_solver(T, t, beta, PeInv, solver_parameters, *, t1, INLET1, t2, INLET2): F_T = AdvectionDiffusionGLS(T, beta, t, PeInv=PeInv) bc1 = fd.DirichletBC(T, t1, INLET1) bc2 = fd.DirichletBC(T, t2, INLET2) bcs = [bc1, bc2] problem_T = fd.NonlinearVariationalProblem(F_T, t, bcs=bcs) return fd.NonlinearVariationalSolver(problem_T, solver_parameters=solver_parameters)
def update_solver(self): """Create solver objects""" self.solver = [] for i in range(self.n_stages): p = firedrake.NonlinearVariationalProblem(self.F[i], self.k[i]) sname = '{:}_stage{:}_'.format(self.name, i) self.solver.append( firedrake.NonlinearVariationalSolver( p, solver_parameters=self.solver_parameters, options_prefix=sname))
def setup(self, **kwargs): r"""Create the internal data structures that help reuse information from past prognostic solves""" for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( "Input %s field has type %s, must be Constant or Function!" % (name, type(field)) ) dt = firedrake.Constant(1.0) h = self._fields["thickness"] u = self._fields["velocity"] h_0 = h.copy(deepcopy=True) Q = h.function_space() mesh = Q.mesh() n = FacetNormal(mesh) outflow = firedrake.max_value(0, inner(u, n)) inflow = firedrake.min_value(0, inner(u, n)) # Additional streamlining terms that give 2nd-order accuracy q = firedrake.TestFunction(Q) ds = firedrake.ds if mesh.layers is None else firedrake.ds_v flux_cells = -div(h * u) * inner(u, grad(q)) * dx flux_out = div(h * u) * q * outflow * ds flux_in = div(h_0 * u) * q * inflow * ds d2h_dt2 = flux_cells + flux_out + flux_in dh_dt = self._continuity(dt, **self._fields) F = (h - h_0) * q * dx - dt * (dh_dt + 0.5 * dt * d2h_dt2) problem = firedrake.NonlinearVariationalProblem(F, h) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters ) self._thickness_old = h_0 self._timestep = dt
def _setup(self, **kwargs): q = kwargs["q"].copy(deepcopy=True) f = kwargs["f"].copy(deepcopy=True) u = kwargs["u"].copy(deepcopy=True) L = self.model.action(u=u, q=q, f=f) F = firedrake.derivative(L, u) V = u.function_space() bc = firedrake.DirichletBC(V, u, self.dirichlet_ids) params = { "solver_parameters": { "ksp_type": "preonly", "pc_type": "lu" } } problem = firedrake.NonlinearVariationalProblem(F, u, bc) self._solver = firedrake.NonlinearVariationalSolver(problem, **params) self._fields = {"q": q, "f": f, "u": u}
def test_solver_no_flow_region(): mesh = fd.Mesh("./2D_mesh.msh") no_flow = [2] no_flow_markers = [1] mesh = mark_no_flow_regions(mesh, no_flow, no_flow_markers) P2 = fd.VectorElement("CG", mesh.ufl_cell(), 1) P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1) TH = P2 * P1 W = fd.FunctionSpace(mesh, TH) (v, q) = fd.TestFunctions(W) # Stokes 1 w_sol1 = fd.Function(W) nu = fd.Constant(0.05) F = NavierStokesBrinkmannForm(W, w_sol1, nu, beta_gls=2.0) x, y = fd.SpatialCoordinate(mesh) u_mms = fd.as_vector( [sin(2.0 * pi * x) * sin(pi * y), sin(pi * x) * sin(2.0 * pi * y)]) p_mms = -0.5 * (u_mms[0]**2 + u_mms[1]**2) f_mms_u = (grad(u_mms) * u_mms + grad(p_mms) - 2.0 * nu * div(sym(grad(u_mms)))) f_mms_p = div(u_mms) F += -inner(f_mms_u, v) * dx - f_mms_p * q * dx bc1 = fd.DirichletBC(W.sub(0), u_mms, "on_boundary") bc2 = fd.DirichletBC(W.sub(1), p_mms, "on_boundary") bc_no_flow = InteriorBC(W.sub(0), fd.Constant((0.0, 0.0)), no_flow_markers) solver_parameters = {"ksp_max_it": 500, "ksp_monitor": None} problem1 = fd.NonlinearVariationalProblem(F, w_sol1, bcs=[bc1, bc2, bc_no_flow]) solver1 = NavierStokesBrinkmannSolver( problem1, options_prefix="navier_stokes", solver_parameters=solver_parameters, ) solver1.solve() u_sol, _ = w_sol1.split() u_mms_func = fd.interpolate(u_mms, W.sub(0)) error = fd.errornorm(u_sol, u_mms_func) assert error < 0.07
def setup(self, **kwargs): r"""Create the internal data structures that help reuse information from past prognostic solves""" for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( 'Input fields must be Constant or Function!') dt = firedrake.Constant(1.) h = self._fields.get('thickness', self._fields.get('h')) u = self._fields.get('velocity', self._fields.get('u')) h_0 = h.copy(deepcopy=True) Q = h.function_space() model = self._continuity n = model.facet_normal(Q.mesh()) outflow = firedrake.max_value(0, inner(u, n)) inflow = firedrake.min_value(0, inner(u, n)) # Additional streamlining terms that give 2nd-order accuracy q = firedrake.TestFunction(Q) div, grad, ds = model.div, model.grad, model.ds flux_cells = -div(h * u) * inner(u, grad(q)) * dx flux_out = div(h * u) * q * outflow * ds flux_in = div(h_0 * u) * q * inflow * ds d2h_dt2 = flux_cells + flux_out + flux_in dh_dt = model(dt, **self._fields) F = (h - h_0) * q * dx - dt * (dh_dt + 0.5 * dt * d2h_dt2) problem = firedrake.NonlinearVariationalProblem(F, h) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters) self._thickness_old = h_0 self._timestep = dt
def run_solver(r): mesh = fd.UnitSquareMesh(2**r, 2**r) P2 = fd.VectorElement("CG", mesh.ufl_cell(), 1) P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1) TH = P2 * P1 W = fd.FunctionSpace(mesh, TH) (v, q) = fd.TestFunctions(W) # Stokes 1 w_sol1 = fd.Function(W) nu = fd.Constant(0.05) F = NavierStokesBrinkmannForm(W, w_sol1, nu, beta_gls=2.0) from firedrake import sin, grad, pi, sym, div, inner x, y = fd.SpatialCoordinate(mesh) u_mms = fd.as_vector( [sin(2.0 * pi * x) * sin(pi * y), sin(pi * x) * sin(2.0 * pi * y)]) p_mms = -0.5 * (u_mms[0]**2 + u_mms[1]**2) f_mms_u = (grad(u_mms) * u_mms + grad(p_mms) - 2.0 * nu * div(sym(grad(u_mms)))) f_mms_p = div(u_mms) F += -inner(f_mms_u, v) * dx - f_mms_p * q * dx bc1 = fd.DirichletBC(W.sub(0), u_mms, "on_boundary") bc2 = fd.DirichletBC(W.sub(1), p_mms, "on_boundary") solver_parameters = {"ksp_max_it": 200} problem1 = fd.NonlinearVariationalProblem(F, w_sol1, bcs=[bc1, bc2]) solver1 = NavierStokesBrinkmannSolver( problem1, options_prefix="navier_stokes", solver_parameters=solver_parameters, ) solver1.solve() u_sol, _ = w_sol1.split() fd.File("test_u_sol.pvd").write(u_sol) u_mms_func = fd.interpolate(u_mms, W.sub(0)) error = fd.errornorm(u_sol, u_mms_func) print(f"Error: {error}") return error
def coarsen_problem(problem): u = problem.u h, lvl = utils.get_level(u) if lvl == -1: raise RuntimeError("No hierarchy to coarsen") if lvl == 0: return None new_u = ufl_utils.coarsen_thing(problem.u) new_bcs = [ufl_utils.coarsen_thing(bc) for bc in problem.bcs] new_J = ufl_utils.coarsen_form(problem.J) new_Jp = ufl_utils.coarsen_form(problem.Jp) new_F = ufl_utils.coarsen_form(problem.F) new_problem = firedrake.NonlinearVariationalProblem(new_F, new_u, bcs=new_bcs, J=new_J, Jp=new_Jp, form_compiler_parameters=problem.form_compiler_parameters, nest=problem._nest) return new_problem
def setup(self, **kwargs): r"""Create the internal data structures that help reuse information from past prognostic solves""" for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: self._fields[name] = utilities.copy(field) dt = firedrake.Constant(1.) dh_dt = self._continuity(dt, **self._fields) h = self._fields.get('thickness', self._fields.get('h')) h_0 = h.copy(deepcopy=True) q = firedrake.TestFunction(h.function_space()) F = (h - h_0) * q * dx - dt * dh_dt problem = firedrake.NonlinearVariationalProblem(F, h) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters) self._thickness_old = h_0 self._timestep = dt
def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( 'Input fields must be Constant or Function!') # Create homogeneous BCs for the Dirichlet part of the boundary u = self._fields.get('velocity', self._fields.get('u')) V = u.function_space() bcs = firedrake.DirichletBC(V, u, self._dirichlet_ids) if not self._dirichlet_ids: bcs = None # Find the numeric IDs for the ice front boundary_ids = u.ufl_domain().exterior_facets.unique_markers ice_front_ids_comp = set(self._dirichlet_ids + self._side_wall_ids) ice_front_ids = list(set(boundary_ids) - ice_front_ids_comp) # Create the action and scale functionals _kwargs = { 'side_wall_ids': self._side_wall_ids, 'ice_front_ids': ice_front_ids } action = self._model.action(**self._fields, **_kwargs) F = firedrake.derivative(action, u) degree = self._model.quadrature_degree(**self._fields) params = {'form_compiler_parameters': {'quadrature_degree': degree}} problem = firedrake.NonlinearVariationalProblem(F, u, bcs, **params) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters)
def flow_solver( W, w_sol, no_flow=None, phi=None, beta_gls=0.9, design_domain=None, solver_parameters=None, brinkmann_penalty=0.0, *, inflow, inlet, walls, nu, ): F = NavierStokesBrinkmannForm( W, w_sol, nu, phi=phi, brinkmann_penalty=brinkmann_penalty, design_domain=design_domain, beta_gls=beta_gls, ) noslip = fd.Constant((0.0, 0.0, 0.0)) bcs_1 = fd.DirichletBC(W.sub(0), noslip, walls) bcs_2 = fd.DirichletBC(W.sub(0), inflow, inlet) bcs = [bcs_1, bcs_2] if no_flow: bcs_no_flow = InteriorBC(W.sub(0), noslip, no_flow) bcs.append(bcs_no_flow) problem = fd.NonlinearVariationalProblem(F, w_sol, bcs=bcs) return NavierStokesBrinkmannSolver(problem, solver_parameters=solver_parameters)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.mesh_m = self.Q.mesh_m # Setup problem self.V = fd.FunctionSpace(self.mesh_m, "CG", 1) # Preallocate solution variables for state and adjoint equations self.solution = fd.Function(self.V, name="State") # Weak form of Poisson problem u = self.solution v = fd.TestFunction(self.V) self.f = fd.Constant(4.) self.F = (fd.inner(fd.grad(u), fd.grad(v)) - self.f * v) * fd.dx self.bcs = fd.DirichletBC(self.V, 0., "on_boundary") # PDE-solver parameters self.params = { "ksp_type": "cg", "mat_type": "aij", "pc_type": "hypre", "pc_factor_mat_solver_package": "boomerang", "ksp_rtol": 1e-11, "ksp_atol": 1e-11, "ksp_stol": 1e-15, } stateproblem = fd.NonlinearVariationalProblem( self.F, self.solution, bcs=self.bcs) self.solver = fd.NonlinearVariationalSolver( stateproblem, solver_parameters=self.params) # target function, exact soln is disc of radius 0.6 centered at # (0.5,0.5) (x, y) = fd.SpatialCoordinate(self.mesh_m) self.u_target = 0.36 - (x-0.5)*(x-0.5) - (y-0.5)*(y-0.5)
def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( "Input %s field has type %s, must be Constant or Function!" % (name, type(field)) ) # Create homogeneous BCs for the Dirichlet part of the boundary u = self._fields["velocity"] V = u.function_space() bcs = firedrake.DirichletBC(V, u, self._dirichlet_ids) if not self._dirichlet_ids: bcs = None # Find the numeric IDs for the ice front boundary_ids = u.ufl_domain().exterior_facets.unique_markers ice_front_ids_comp = set(self._dirichlet_ids + self._side_wall_ids) ice_front_ids = list(set(boundary_ids) - ice_front_ids_comp) # Create the action and scale functionals _kwargs = {"side_wall_ids": self._side_wall_ids, "ice_front_ids": ice_front_ids} action = self._model.action(**self._fields, **_kwargs) F = firedrake.derivative(action, u) problem = firedrake.NonlinearVariationalProblem(F, u, bcs) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters )
def solve(self) -> fe.Function: """Set up the problem and solver, and solve. This is a JIT (just in time), ensuring that the problem and solver setup are up-to-date before calling the solver. All compiled objects are cached, so the JIT problem and solver setup does not have any significant performance overhead. """ problem = fe.NonlinearVariationalProblem( F=self.weak_form_residual(), u=self.solution, bcs=self.dirichlet_boundary_conditions(), J=fe.derivative(self.weak_form_residual(), self.solution)) solver = fe.NonlinearVariationalSolver( problem=problem, nullspace=self.nullspace(), solver_parameters=self.solver_parameters) solver.solve() self.snes_iteration_count += solver.snes.getIterationNumber() return self.solution
def __init__(self, problem, u_degree=1, p_degree=1, lambda_degree=1, method="cgls"): self.problem = problem self.method = method mesh = problem.mesh bcs_p = problem.bcs_p bcs_u = problem.bcs_u if method == "cgls": pressure_family = "CG" velocity_family = "CG" dirichlet_method = "topological" elif method == "dgls": pressure_family = "DG" velocity_family = "DG" dirichlet_method = "geometric" elif method == "sdhm": pressure_family = "DG" velocity_family = "DG" trace_family = "HDiv Trace" dirichlet_method = "topological" else: raise ValueError( f"Invalid FEM for solving Darcy Flow. Method provided: {method}" ) self._U = fire.VectorFunctionSpace(mesh, velocity_family, u_degree) self._V = fire.FunctionSpace(mesh, pressure_family, p_degree) if method == "cgls" or method == "dgls": self._W = self._U * self._V if method == "sdhm": self._T = fire.FunctionSpace(mesh, trace_family, lambda_degree) self._W = self._U * self._V * self._T self.solution = fire.Function(self._W) if method == "cgls": self.u, self.p = self.solution.split() self._a, self._L = self.cgls_form(problem, mesh, bcs_p) if method == "dgls": self.u, self.p = self.solution.split() self._a, self._L = self.dgls_form(problem, mesh, bcs_p) if method == "sdhm": self.u, self.p, self.tracer = self.solution.split() self._a, self._L = self.sdhm_form(problem, mesh, bcs_p, bcs_u) self.u.rename("u", "label") self.p.rename("p", "label") if method == "sdhm": self.solver_parameters = { "snes_type": "ksponly", "mat_type": "matfree", "pmat_type": "matfree", "ksp_type": "preonly", "pc_type": "python", # Use the static condensation PC for hybridized problems # and use a direct solve on the reduced system for lambda_h "pc_python_type": "firedrake.SCPC", "pc_sc_eliminate_fields": "0, 1", "condensed_field": { "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps", }, } F = self._a - self._L nvp = fire.NonlinearVariationalProblem(F, self.solution) self.solver = fire.NonlinearVariationalSolver( nvp, solver_parameters=self.solver_parameters) else: self.bcs = [] rho = self.problem.rho for uboundary, iboundary, component in bcs_u: if component is not None: self.bcs.append( DirichletExpressionBC( self._W.sub(0).sub(component), rho * uboundary, iboundary, method=dirichlet_method, )) else: self.bcs.append( DirichletExpressionBC(self._W.sub(0), rho * uboundary, iboundary, method=dirichlet_method)) # self.solver_parameters = { # # This setup is suitable for 3D # 'ksp_type': 'lgmres', # 'pc_type': 'lu', # 'mat_type': 'aij', # 'ksp_rtol': 1e-8, # 'ksp_max_it': 2000, # 'ksp_monitor': None # } self.solver_parameters = { "mat_type": "aij", "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps", } lvp = fire.LinearVariationalProblem(self._a, self._L, self.solution, bcs=self.bcs) self.solver = fire.LinearVariationalSolver( lvp, solver_parameters=self.solver_parameters)
def test_set_para_form_mixed(): # checks that the all-at-once system is the same as solving # timesteps sequentially using the mixed wave equation as an # example by substituting the sequential solution and evaluating # the residual mesh = fd.PeriodicUnitSquareMesh(20, 20) V = fd.FunctionSpace(mesh, "BDM", 1) Q = fd.FunctionSpace(mesh, "DG", 0) W = V * Q x, y = fd.SpatialCoordinate(mesh) w0 = fd.Function(W) u0, p0 = w0.split() p0.interpolate(fd.exp(-((x - 0.5)**2 + (y - 0.5)**2) / 0.5**2)) dt = 0.01 theta = 0.5 alpha = 0.001 M = 4 solver_parameters = { 'ksp_type': 'gmres', 'pc_type': 'none', 'ksp_rtol': 1.0e-8, 'ksp_atol': 1.0e-8, 'ksp_monitor': None } def form_function(uu, up, vu, vp): return (fd.div(vu) * up - fd.div(uu) * vp) * fd.dx def form_mass(uu, up, vu, vp): return (fd.inner(uu, vu) + up * vp) * fd.dx PD = asQ.paradiag(form_function=form_function, form_mass=form_mass, W=W, w0=w0, dt=dt, theta=theta, alpha=alpha, M=M, solver_parameters=solver_parameters, circ="none") # sequential solver un = fd.Function(W) unp1 = fd.Function(W) un.assign(w0) v = fd.TestFunction(W) eqn = (1.0 / dt) * form_mass(*(fd.split(unp1)), *(fd.split(v))) eqn -= (1.0 / dt) * form_mass(*(fd.split(un)), *(fd.split(v))) eqn += fd.Constant( (1 - theta)) * form_function(*(fd.split(un)), *(fd.split(v))) eqn += fd.Constant(theta) * form_function(*(fd.split(unp1)), *(fd.split(v))) sprob = fd.NonlinearVariationalProblem(eqn, unp1) solver_parameters = { 'ksp_type': 'preonly', 'pc_type': 'lu', 'pc_factor_mat_solver_type': 'mumps', 'mat_type': 'aij' } ssolver = fd.NonlinearVariationalSolver( sprob, solver_parameters=solver_parameters) for i in range(M): ssolver.solve() for k in range(2): PD.w_all.sub(2 * i + k).assign(unp1.sub(k)) un.assign(unp1) Pres = fd.assemble(PD.para_form) for i in range(M): assert (dt * np.abs(Pres.sub(i).dat.data[:]).max() < 1.0e-16)
def test_quasi(): # tests the quasi-Newton option # using the heat equation as an example mesh = fd.UnitSquareMesh(20, 20) V = fd.FunctionSpace(mesh, "CG", 1) x, y = fd.SpatialCoordinate(mesh) u0 = fd.Function(V).interpolate( fd.exp(-((x - 0.5)**2 + (y - 0.5)**2) / 0.5**2)) dt = 0.01 theta = 0.5 alpha = 0.001 M = 4 solver_parameters = { 'ksp_type': 'preonly', 'pc_type': 'lu', 'pc_factor_mat_solver_type': 'mumps', 'mat_type': 'aij', 'snes_monitor': None } # Solving U_t + F(U) = 0 # defining F(U) def form_function(u, v): return fd.inner(fd.grad(u), fd.grad(v)) * fd.dx # defining the structure of U_t def form_mass(u, v): return u * v * fd.dx PD = asQ.paradiag(form_function=form_function, form_mass=form_mass, W=V, w0=u0, dt=dt, theta=theta, alpha=alpha, M=M, solver_parameters=solver_parameters, circ="quasi") PD.solve() # sequential solver un = fd.Function(V) unp1 = fd.Function(V) un.assign(u0) v = fd.TestFunction(V) eqn = (unp1 - un) * v * fd.dx eqn += fd.Constant(dt * (1 - theta)) * form_function(un, v) eqn += fd.Constant(dt * theta) * form_function(unp1, v) sprob = fd.NonlinearVariationalProblem(eqn, unp1) solver_parameters = {'ksp_type': 'preonly', 'pc_type': 'lu'} ssolver = fd.NonlinearVariationalSolver( sprob, solver_parameters=solver_parameters) err = fd.Function(V, name="err") pun = fd.Function(V, name="pun") for i in range(M): ssolver.solve() un.assign(unp1) pun.assign(PD.w_all.sub(i)) err.assign(un - pun) assert (fd.norm(err) < 1.0e-10)
def coarsen(self, fdm, comm): fctx = get_appctx(fdm) test, trial = fctx.J.arguments() fV = test.function_space() fu = fctx._problem.u cele = self.coarsen_element(fV.ufl_element()) cV = firedrake.FunctionSpace(fV.mesh(), cele) cdm = cV.dm cu = firedrake.Function(cV) interpolators = tuple( firedrake.Interpolator(fus, cus) for fus, cus in zip(fu.split(), cu.split())) def inject_state(interpolators): for interpolator in interpolators: interpolator.interpolate() parent = get_parent(fdm) assert parent is not None add_hook(parent, setup=partial(push_parent, cdm, parent), teardown=partial(pop_parent, cdm, parent), call_setup=True) replace_d = { fu: cu, test: firedrake.TestFunction(cV), trial: firedrake.TrialFunction(cV) } cJ = replace(fctx.J, replace_d) cF = replace(fctx.F, replace_d) if fctx.Jp is not None: cJp = replace(fctx.Jp, replace_d) else: cJp = None cbcs = [] for bc in fctx._problem.bcs: # Don't actually need the value, since it's only used for # killing parts of the matrix. This should be generalised # for p-FAS, if anyone ever wants to do that cV_ = cV for index in bc._indices: cV_ = cV_.sub(index) cbcs.append( firedrake.DirichletBC(cV_, firedrake.zero(cV_.shape), bc.sub_domain, method=bc.method)) fcp = fctx._problem.form_compiler_parameters cproblem = firedrake.NonlinearVariationalProblem( cF, cu, cbcs, cJ, Jp=cJp, form_compiler_parameters=fcp, is_linear=fctx._problem.is_linear) cctx = _SNESContext( cproblem, fctx.mat_type, fctx.pmat_type, appctx=fctx.appctx, pre_jacobian_callback=fctx._pre_jacobian_callback, pre_function_callback=fctx._pre_function_callback, post_jacobian_callback=fctx._post_jacobian_callback, post_function_callback=fctx._post_function_callback, options_prefix=fctx.options_prefix, transfer_manager=fctx.transfer_manager) add_hook(parent, setup=partial(push_appctx, cdm, cctx), teardown=partial(pop_appctx, cdm, cctx), call_setup=True) add_hook(parent, setup=partial(inject_state, interpolators), call_setup=True) cdm.setKSPComputeOperators(_SNESContext.compute_operators) cdm.setCreateInterpolation(self.create_interpolation) cdm.setOptionsPrefix(fdm.getOptionsPrefix()) # If we're the coarsest grid of the p-hierarchy, don't # overwrite the coarsen routine; this is so that you can # use geometric multigrid for the p-coarse problem try: self.coarsen_element(cele) cdm.setCoarsen(self.coarsen) except ValueError: pass return cdm
def initial_values(sim): print("Solving steady heat driven cavity to obtain initial values") Ra = 2.518084e6 Pr = 6.99 sim.reference_temperature_range__degC.assign(10.) sim.grashof_number = sim.grashof_number.assign(Ra / Pr) sim.prandtl_number = sim.prandtl_number.assign(Pr) w = fe.Function(sim.function_space) p, u, T = w.split() p.assign(0.) ihat, jhat = sim.unit_vectors() u.assign(0. * ihat + 0. * jhat) T.assign(sim.cold_wall_temperature) F = heat_driven_cavity_variational_form_residual( sim=sim, solution=w) * fe.dx(degree=sim.quadrature_degree) problem = fe.NonlinearVariationalProblem( F=F, u=w, bcs=dirichlet_boundary_conditions(sim), J=fe.derivative(F, w)) solver = fe.NonlinearVariationalSolver(problem=problem, solver_parameters={ "snes_type": "newtonls", "snes_monitor": None, "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "pc_factor_mat_solver_type": "mumps" }) def solve(): solver.solve() return w w, _ = \ sapphire.continuation.solve_with_bounded_regularization_sequence( solve = solve, solution = w, backup_solution = fe.Function(w), regularization_parameter = sim.grashof_number, initial_regularization_sequence = ( 0., sim.grashof_number.__float__())) return w
def main(): mesh = fd.Mesh("./mesh_stokes.msh") mh = fd.MeshHierarchy(mesh, 1) mesh = mh[-1] # mesh = fd.Mesh("./mesh_stokes_inlets.msh") S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) x, y = fd.SpatialCoordinate(mesh) PHI = fd.FunctionSpace(mesh, "DG", 1) lx = 1.0 # phi_expr = -0.5 * cos(3.0 / lx * pi * x + 1.0) * cos(3.0 * pi * y) - 0.3 lx = 2.0 phi_expr = -cos(6.0 / lx * pi * x + 1.0) * cos(4.0 * pi * y) - 0.6 with stop_annotating(): phi = fd.interpolate(phi_expr, PHI) phi.rename("LevelSet") nu = fd.Constant(1.0) V = fd.VectorFunctionSpace(mesh, "CG", 1) P = fd.FunctionSpace(mesh, "CG", 1) W = V * P w_sol = fd.Function(W) brinkmann_penalty = 1e6 F = NavierStokesBrinkmannForm(W, w_sol, phi, nu, brinkmann_penalty=brinkmann_penalty) x, y = fd.SpatialCoordinate(mesh) u_inflow = 1.0 y_inlet_1_1 = 0.2 y_inlet_1_2 = 0.4 inflow1 = fd.as_vector([ u_inflow * 100 * (y - y_inlet_1_1) * (y - y_inlet_1_2), 0.0, ]) y_inlet_2_1 = 0.6 y_inlet_2_2 = 0.8 inflow2 = fd.as_vector([ u_inflow * 100 * (y - y_inlet_2_1) * (y - y_inlet_2_2), 0.0, ]) noslip = fd.Constant((0.0, 0.0)) bc1 = fd.DirichletBC(W.sub(0), noslip, 5) bc2 = fd.DirichletBC(W.sub(0), inflow1, (1)) bc3 = fd.DirichletBC(W.sub(0), inflow2, (2)) bcs = [bc1, bc2, bc3] problem = fd.NonlinearVariationalProblem(F, w_sol, bcs=bcs) solver_parameters = { "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "ksp_converged_reason": None, "pc_factor_mat_solver_type": "mumps", } # solver_parameters = { # "ksp_type": "fgmres", # "pc_type": "hypre", # "pc_hypre_type": "euclid", # "pc_hypre_euclid_level": 5, # "mat_type": "aij", # "ksp_converged_reason": None, # "ksp_atol": 1e-3, # "ksp_rtol": 1e-3, # "snes_atol": 1e-3, # "snes_rtol": 1e-3, # } solver = NavierStokesBrinkmannSolver(problem, solver_parameters=solver_parameters) solver.solve() pvd_file = fd.File("ns_solution.pvd") u, p = w_sol.split() pvd_file.write(u, p) u, p = fd.split(w_sol) Vol = fd.assemble(hs(-phi) * fd.Constant(1.0) * dx(0, domain=mesh)) VControl = fda.Control(Vol) Vval = fd.assemble(fd.Constant(0.5) * dx(domain=mesh), annotate=False) with stop_annotating(): print("Initial constraint function value {}".format(Vol)) J = fd.assemble( fd.Constant(brinkmann_penalty) * hs(phi) * inner(u, u) * dx(0) + nu / fd.Constant(2.0) * inner(grad(u), grad(u)) * dx) c = fda.Control(s) phi_pvd = fd.File("phi_evolution_euclid.pvd", target_continuity=fd.H1) def deriv_cb(phi): with stop_annotating(): phi_pvd.write(phi[0]) Jhat = LevelSetFunctional(J, c, phi, derivative_cb_pre=deriv_cb) Vhat = LevelSetFunctional(Vol, c, phi) bcs_vel_1 = fd.DirichletBC(S, noslip, (1, 2, 3, 4)) bcs_vel = [bcs_vel_1] reg_solver = RegularizationSolver(S, mesh, beta=0.5, gamma=1e5, dx=dx, bcs=bcs_vel, design_domain=0) tol = 1e-5 dt = 0.0002 params = { "alphaC": 1.0, "debug": 5, "alphaJ": 1.0, "dt": dt, "K": 0.1, "maxit": 2000, "maxtrials": 5, "itnormalisation": 10, "tol_merit": 1e-4, # new merit can be within 5% of the previous merit # "normalize_tol" : -1, "tol": tol, } problem = InfDimProblem( Jhat, reg_solver, ineqconstraints=[Constraint(Vhat, Vval, VControl)], ) _ = nullspace_shape(problem, params)
element = fe.FiniteElement("P", mesh.ufl_cell(), 1) V = fe.FunctionSpace(mesh, element) u = fe.Function(V) v = fe.TestFunction(V) bc = fe.DirichletBC(V, 0., "on_boundary") alpha = 1 + u/10. x = fe.SpatialCoordinate(mesh)[0] div, grad, dot, sin, pi, dx = fe.div, fe.grad, fe.dot, fe.sin, fe.pi, fe.dx f = 10.*sin(pi*x) R = (-dot(grad(v), alpha*grad(u)) - v*f)*dx problem = fe.NonlinearVariationalProblem(R, u, bc, fe.derivative(R, u)) solver = fe.NonlinearVariationalSolver( problem, solver_parameters = {"snes_monitor": True}) solver.solve() print("u_h = " + str(u.vector()[:]))
- q*f*fd.dx + fd.Constant(pbar)*fd.inner(v, n)*fd.ds(outlet) # Upwind normal velocity: (dot(vD, n) + |dot(vD, n)|)/2.0 un = 0.5 * (fd.dot(u0, n) + abs(fd.dot(u0, n))) F_s = r*phi*(s - s0)*fd.dx - \ dtc*(fd.dot(fd.grad(r), Fw(s_mid)*u)*fd.dx - r*Fw(s_mid)*un*fd.ds - fd.conditional(fd.dot(u0, n) < 0, r * fd.dot(u0, n)*Fw(s_in), 0.0)*fd.ds - (r('+') - r('-'))*(un('+')*Fw(s_mid)('+') - un('-')*Fw(s_mid)('-'))*fd.dS) # Res. R = F_p + F_s prob = fd.NonlinearVariationalProblem(R, U, bcs=[bc0, bc1, bc3]) solver2ph = fd.NonlinearVariationalSolver(prob) # %% # 4) Solve problem # initialize variables xv, xp, xs = U.split() vel = fd.project(u0, P1) xp.rename('pressure') xs.rename('saturation') vel.rename('velocity') outfile = fd.File(oFile) it = 0 t = 0.0 while t < sim_time:
# shock capturing parameters if add_shock_term: cnorm = fd.sqrt(fd.dot(fd.grad(c0), fd.grad(c0))) vshock = fd.conditional( fd.gt(cnorm, 1e-15), beta * h / (2 * cnorm), # *cnorm, fd.Constant(0.)) # shock terms # F1 += vshock*fd.dot(fd.grad(w), fd.grad(c_mid))*fd.dx F1 += vshock * np.abs(R) * fd.inner(fd.grad(w), fd.grad(c_mid)) * fd.dx F = F1 prob = fd.NonlinearVariationalProblem(F, c, bcs=t_bc) transport = fd.NonlinearVariationalSolver(prob) # %% # 4) Solve problem c0.assign(0.) t = it = 0 outfile = fd.File("plots/adr_supg_shock.pvd") c0.rename("c") dt = CFL * fd.interpolate(h / vnorm, DG0).dat.data.min() Dt.assign(dt) dt0 = dt Pe = vnorm * h / (2.0 * Diff) print('Peclet = {}; dt = {}'.format(
def compliance_optimization(n_iters=200): output_dir = "cantilever/" path = os.path.abspath(__file__) dir_path = os.path.dirname(path) m = fd.Mesh(f"{dir_path}/mesh_cantilever.msh") mesh = fd.MeshHierarchy(m, 0)[-1] # Perturb the mesh coordinates. Necessary to calculate shape derivatives S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) # Initial level set function x, y = fd.SpatialCoordinate(mesh) PHI = fd.FunctionSpace(mesh, "CG", 1) lx = 2.0 ly = 1.0 phi_expr = ( -cos(6.0 / lx * pi * x) * cos(4.0 * pi * y) - 0.6 + max_value(200.0 * (0.01 - x ** 2 - (y - ly / 2) ** 2), 0.0) + max_value(100.0 * (x + y - lx - ly + 0.1), 0.0) + max_value(100.0 * (x - y - lx + 0.1), 0.0) ) # Avoid recording the operation interpolate into the tape. # Otherwise, the shape derivatives will not be correct with fda.stop_annotating(): phi = fd.interpolate(phi_expr, PHI) phi.rename("LevelSet") fd.File(output_dir + "phi_initial.pvd").write(phi) # Physics. Elasticity rho_min = 1e-5 beta = fd.Constant(200.0) def hs(phi, beta): return fd.Constant(1.0) / ( fd.Constant(1.0) + exp(-beta * phi) ) + fd.Constant(rho_min) H1_elem = fd.VectorElement("CG", mesh.ufl_cell(), 1) W = fd.FunctionSpace(mesh, H1_elem) u = fd.TrialFunction(W) v = fd.TestFunction(W) # Elasticity parameters E, nu = 1.0, 0.3 mu, lmbda = fd.Constant(E / (2 * (1 + nu))), fd.Constant( E * nu / ((1 + nu) * (1 - 2 * nu)) ) def epsilon(u): return sym(nabla_grad(u)) def sigma(v): return 2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(2) a = inner(hs(-phi, beta) * sigma(u), nabla_grad(v)) * dx t = fd.Constant((0.0, -75.0)) L = inner(t, v) * ds(2) bc = fd.DirichletBC(W, fd.Constant((0.0, 0.0)), 1) parameters = { "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "ksp_converged_reason": None, "pc_factor_mat_solver_type": "mumps", } u_sol = fd.Function(W) F = fd.action(a, u_sol) - L problem = fd.NonlinearVariationalProblem(F, u_sol, bcs=bc) solver = fd.NonlinearVariationalSolver( problem, solver_parameters=parameters ) solver.solve() # fd.solve( # a == L, u_sol, bcs=[bc], solver_parameters=parameters # ) # , nullspace=nullspace) with fda.stop_annotating(): fd.File("u_sol.pvd").write(u_sol) # Cost function: Compliance J = fd.assemble( fd.Constant(1e-2) * inner(hs(-phi, beta) * sigma(u_sol), epsilon(u_sol)) * dx ) # Constraint: Volume with fda.stop_annotating(): total_volume = fd.assemble(fd.Constant(1.0) * dx(domain=mesh)) VolPen = fd.assemble(hs(-phi, beta) * dx) # Needed to track the value of the volume VolControl = fda.Control(VolPen) Vval = total_volume / 2.0 phi_pvd = fd.File("phi_evolution.pvd", target_continuity=fd.H1) def deriv_cb(phi): with fda.stop_annotating(): phi_pvd.write(phi[0]) c = fda.Control(s) Jhat = LevelSetFunctional(J, c, phi, derivative_cb_pre=deriv_cb) Vhat = LevelSetFunctional(VolPen, c, phi) beta_param = 0.1 # Boundary conditions for the shape derivatives. # They must be zero at the boundary conditions. bcs_vel = fd.DirichletBC(S, fd.Constant((0.0, 0.0)), (1, 2)) # Regularize the shape derivatives reg_solver = RegularizationSolver( S, mesh, beta=beta_param, gamma=1.0e5, dx=dx, bcs=bcs_vel, output_dir=None, ) # Hamilton-Jacobi equation to advect the level set dt = 0.05 tol = 1e-5 # Optimization problem vol_constraint = Constraint(Vhat, Vval, VolControl) problem = InfDimProblem(Jhat, reg_solver, ineqconstraints=vol_constraint) parameters = { "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "ksp_converged_reason": None, "pc_factor_mat_solver_type": "mumps", } params = { "alphaC": 3.0, "K": 0.1, "debug": 5, "alphaJ": 1.0, "dt": dt, "maxtrials": 10, "maxit": n_iters, "itnormalisation": 50, "tol": tol, } results = nlspace_solve(problem, params) return results
G_q = mu_h*fd.inner(Diff*fd.grad(ch) + velocity * ch, n)*fd.ds(outflow) + \ mu_h*fd.Constant(no_flow)*fd.ds(TOP) + \ mu_h*fd.Constant(no_flow)*fd.ds(BOTTOM) # G_q = 0 a = a_u + a_c + F_q L = L_u + L_c + G_q # %% # 4) Solve problem # solve # set boundary conditions bc = fd.DirichletBC(W.sub(2), cIn, inlet) problem = fd.NonlinearVariationalProblem(a - L, w, bcs=bc) rtol = 1e-4 # sparse_plt.plot_matrix(a, bcs=bc) # plt.show() # sparse_plt.plot_matrix_hybrid_multiplier_spp(a, bcs=bc) # plt.show() hybrid_solver_params = { "snes_type": "ksponly", "mat_type": "matfree", "pmat_type": "matfree", "ksp_type": "preonly", "pc_type": "python", # Use the static condensation PC for hybridized problems # and use a direct solve on the reduced system for lambda_h
F_a = Dt*((r('+') - r('-'))*(vn('+')*c_mid('+') - vn('-')*c_mid('-'))*fd.dS - fd.div(u*r)*c_mid*fd.dx + fd.conditional(fd.dot(u0, n) < 0, r * fd.dot(u0, n)*cIn, 0.0)*fd.ds + fd.conditional(fd.dot(u0, n) > 0, r * fd.dot(u0, n)*c, 0.0)*fd.ds) # full weak form F = F_sb + F_t + F_a + F_d # assign problem and solver dw = fd.TrialFunction(W) J = fd.derivative(F, w, dw) problem = fd.NonlinearVariationalProblem(F, w, bcs, J) param = { 'snes_type': 'newtonls', 'snes_max_it': 100, 'ksp_type': 'gmres', 'ksp_rtol': 1e-3 } solver = fd.NonlinearVariationalSolver(problem, solver_parameters=param) # %% # 4) Solve problem # ----------------- wave_speed = fd.conditional(fd.lt(abs(vnorm), tol), h_E/tol, h_E/vnorm) outfile = fd.File("plots/sb_adr_fi.pvd")
def compute_time_accuracy_via_mms( gridsize, element_degree, timestep_sizes, endtime): mesh = fe.UnitIntervalMesh(gridsize) element = fe.FiniteElement("P", mesh.ufl_cell(), element_degree) V = fe.FunctionSpace(mesh, element) u_h = fe.Function(V) v = fe.TestFunction(V) un = fe.Function(V) u_m = manufactured_solution(mesh) bc = fe.DirichletBC(V, u_m, "on_boundary") _F = F(u_h, v, un) problem = fe.NonlinearVariationalProblem( _F - v*R(u_m)*dx, u_h, bc, fe.derivative(_F, u_h)) solver = fe.NonlinearVariationalSolver(problem) t.assign(0.) initial_values = fe.interpolate(u_m, V) L2_norm_errors = [] print("Delta_t, L2_norm_error") for timestep_size in timestep_sizes: Delta_t.assign(timestep_size) un.assign(initial_values) time = 0. t.assign(time) while time < (endtime - TIME_EPSILON): time += timestep_size t.assign(time) solver.solve() un.assign(u_h) L2_norm_errors.append( math.sqrt(fe.assemble(fe.inner(u_h - u_m, u_h - u_m)*dx))) print(str(timestep_size) + ", " + str(L2_norm_errors[-1])) r = timestep_sizes[-2]/timestep_sizes[-1] e = L2_norm_errors log = math.log order = log(e[-2]/e[-1])/log(r) return order
def coarsen(self, fdm, comm): # Coarsen the _SNESContext of a DM fdm # return the coarse DM cdm of the coarse _SNESContext fctx = get_appctx(fdm) parent = get_parent(fdm) assert parent is not None test, trial = fctx.J.arguments() fV = test.function_space() cele = self.coarsen_element(fV.ufl_element()) # Have we already done this? cctx = fctx._coarse if cctx is not None: cV = cctx.J.arguments()[0].function_space() if (cV.ufl_element() == cele) and (cV.mesh() == fV.mesh()): return cV.dm cV = firedrake.FunctionSpace(fV.mesh(), cele) cdm = cV.dm fproblem = fctx._problem fu = fproblem.u cu = firedrake.Function(cV) def coarsen_quadrature(df, Nf, Nc): # Coarsen the quadrature degree in a dictionary # such that the ratio of quadrature nodes to interpolation nodes (Nq+1)/(Nf+1) is preserved if isinstance(df, dict): Nq = df.get("quadrature_degree", None) if Nq is not None: dc = dict(df) dc["quadrature_degree"] = max( 2 * Nc + 1, ((Nq + 1) * (Nc + 1) + Nf) // (Nf + 1) - 1) return dc return df def coarsen_form(form, Nf, Nc, replace_d): # Coarsen a form, by replacing the solution, test and trial functions, and # reconstructing each integral with a coarsened quadrature degree. # If form is not a Form, then return form. return Form([ f.reconstruct( metadata=coarsen_quadrature(f.metadata(), Nf, Nc)) for f in replace(form, replace_d).integrals() ]) if isinstance(form, Form) else form def coarsen_bcs(fbcs): cbcs = [] for bc in fbcs: cV_ = cV for index in bc._indices: cV_ = cV_.sub(index) cbc_value = self.coarsen_bc_value(bc, cV_) if type(bc) == firedrake.DirichletBC: cbcs.append( firedrake.DirichletBC(cV_, cbc_value, bc.sub_domain)) else: raise NotImplementedError( "Unsupported BC type, please get in touch if you need this" ) return cbcs Nf = PMGBase.max_degree(fV.ufl_element()) Nc = PMGBase.max_degree(cV.ufl_element()) # Replace dictionary with coarse state, test and trial functions replace_d = { fu: cu, test: firedrake.TestFunction(cV), trial: firedrake.TrialFunction(cV) } cF = coarsen_form(fctx.F, Nf, Nc, replace_d) cJ = coarsen_form(fctx.J, Nf, Nc, replace_d) cJp = coarsen_form(fctx.Jp, Nf, Nc, replace_d) fcp = coarsen_quadrature(fproblem.form_compiler_parameters, Nf, Nc) cbcs = coarsen_bcs(fproblem.bcs) # Coarsen the appctx: the user might want to provide solution-dependant expressions and forms cappctx = dict(fctx.appctx) for key in cappctx: val = cappctx[key] if isinstance(val, dict): cappctx[key] = coarsen_quadrature(val, Nf, Nc) elif isinstance(val, Expr): cappctx[key] = replace(val, replace_d) elif isinstance(val, Form): cappctx[key] = coarsen_form(val, Nf, Nc, replace_d) cmat_type = fctx.mat_type cpmat_type = fctx.pmat_type if Nc == self.coarse_degree: cmat_type = self.coarse_mat_type cpmat_type = self.coarse_mat_type if fcp is None: fcp = dict() fcp["mode"] = self.coarse_form_compiler_mode # Coarsen the problem and the _SNESContext cproblem = firedrake.NonlinearVariationalProblem( cF, cu, bcs=cbcs, J=cJ, Jp=cJp, form_compiler_parameters=fcp, is_linear=fproblem.is_linear) cctx = type(fctx)(cproblem, cmat_type, cpmat_type, appctx=cappctx, pre_jacobian_callback=fctx._pre_jacobian_callback, pre_function_callback=fctx._pre_function_callback, post_jacobian_callback=fctx._post_jacobian_callback, post_function_callback=fctx._post_function_callback, options_prefix=fctx.options_prefix, transfer_manager=fctx.transfer_manager) # FIXME setting up the _fine attribute triggers gmg injection. # cctx._fine = fctx fctx._coarse = cctx add_hook(parent, setup=partial(push_parent, cdm, parent), teardown=partial(pop_parent, cdm, parent), call_setup=True) add_hook(parent, setup=partial(push_appctx, cdm, cctx), teardown=partial(pop_appctx, cdm, cctx), call_setup=True) cdm.setOptionsPrefix(fdm.getOptionsPrefix()) cdm.setKSPComputeOperators(_SNESContext.compute_operators) cdm.setCreateInterpolation(self.create_interpolation) cdm.setCreateInjection(self.create_injection) # If we're the coarsest grid of the p-hierarchy, don't # overwrite the coarsen routine; this is so that you can # use geometric multigrid for the p-coarse problem try: self.coarsen_element(cele) cdm.setCoarsen(self.coarsen) except ValueError: pass # injection of the initial state def inject_state(mat): with cu.dat.vec_wo as xc, fu.dat.vec_ro as xf: mat.multTranspose(xf, xc) injection = self.create_injection(cdm, fdm) add_hook(parent, setup=partial(inject_state, injection), call_setup=True) # restrict the nullspace basis def coarsen_nullspace(coarse_V, mat, fine_nullspace): if isinstance(fine_nullspace, MixedVectorSpaceBasis): if mat.type == 'python': mat = mat.getPythonContext() submats = [ mat.getNestSubMatrix(i, i) for i in range(len(coarse_V)) ] coarse_bases = [] for fs, submat, basis in zip(coarse_V, submats, fine_nullspace._bases): if isinstance(basis, VectorSpaceBasis): coarse_bases.append( coarsen_nullspace(fs, submat, basis)) else: coarse_bases.append(coarse_V.sub(basis.index)) return MixedVectorSpaceBasis(coarse_V, coarse_bases) elif isinstance(fine_nullspace, VectorSpaceBasis): coarse_vecs = [] for xf in fine_nullspace._petsc_vecs: wc = firedrake.Function(coarse_V) with wc.dat.vec_wo as xc: mat.multTranspose(xf, xc) coarse_vecs.append(wc) vsb = VectorSpaceBasis(coarse_vecs, constant=fine_nullspace._constant) vsb.orthonormalize() return vsb else: return fine_nullspace I, _ = self.create_interpolation(cdm, fdm) ises = cV._ises cctx._nullspace = coarsen_nullspace(cV, I, fctx._nullspace) cctx.set_nullspace(cctx._nullspace, ises, transpose=False, near=False) cctx._nullspace_T = coarsen_nullspace(cV, I, fctx._nullspace_T) cctx.set_nullspace(cctx._nullspace_T, ises, transpose=True, near=False) cctx._near_nullspace = coarsen_nullspace(cV, I, fctx._near_nullspace) cctx.set_nullspace(cctx._near_nullspace, ises, transpose=False, near=True) return cdm