def initialize(self, init_solution): self.solution_old.assign(init_solution) u, p = firedrake.split(self.solution) u_old, p_old = self.solution_old.split() u_star_theta = (1-self.theta)*u_old + self.theta*self.u_star u_theta = (1-self.theta)*u_old + self.theta*u p_theta = (1-self.theta_p)*p_old + self.theta_p*p u_lag, p_lag = self.solution_lag.split() u_lag_theta = (1-self.theta)*u_old + self.theta*u_lag p_lag_theta = (1-self.theta_p)*p_old + self.theta_p*p_lag # setup predictor solve, this solves for u_start only using a fixed p_lag_theta for pressure self.fields_star = self.fields.copy() self.fields_star['pressure'] = p_lag_theta self.Fstar = self.equations[0].mass_term(self.u_star_test, self.u_star-u_old) self.Fstar -= self.dt_const*self.equations[0].residual(self.u_star_test, u_star_theta, u_lag_theta, self.fields_star, bcs=self.bcs) self.predictor_problem = firedrake.NonlinearVariationalProblem(self.Fstar, self.u_star) self.predictor_solver = firedrake.NonlinearVariationalSolver(self.predictor_problem, solver_parameters=self.predictor_solver_parameters, options_prefix='predictor_momentum') # the correction solve, solving the coupled system: # u1 = u* - dt*G ( p_theta - p_lag_theta) # div(u1) = 0 self.F = self.equations[0].mass_term(self.u_test, u-self.u_star) pg_term = [term for term in self.equations[0]._terms if isinstance(term, PressureGradientTerm)][0] pg_fields = self.fields.copy() # note that p_theta-p_lag_theta = theta_p*(p1-p_lag) pg_fields['pressure'] = self.theta_p * (p - p_lag) self.F -= self.dt_const*pg_term.residual(self.u_test, u_theta, u_lag_theta, pg_fields, bcs=self.bcs) div_term = [term for term in self.equations[1]._terms if isinstance(term, DivergenceTerm)][0] div_fields = self.fields.copy() div_fields['velocity'] = u self.F -= self.dt_const*div_term.residual(self.p_test, p_theta, p_lag_theta, div_fields, bcs=self.bcs) W = self.solution.function_space() if self.pressure_nullspace is None: mixed_nullspace = None else: mixed_nullspace = firedrake.MixedVectorSpaceBasis(W, [W.sub(0), self.pressure_nullspace]) self.problem = firedrake.NonlinearVariationalProblem(self.F, self.solution) self.solver = firedrake.NonlinearVariationalSolver(self.problem, solver_parameters=self.solver_parameters, appctx={'a': firedrake.derivative(self.F, self.solution), 'schur_nullspace': self.pressure_nullspace, 'dt': self.dt_const, 'dx': self.equations[1].dx, 'ds': self.equations[1].ds, 'bcs': self.bcs, 'n': div_term.n}, nullspace=mixed_nullspace, transpose_nullspace=mixed_nullspace, options_prefix=self.name) self._initialized = True
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.) 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 initialize(self, init_solution): self.solution_old.assign(init_solution) u, p = firedrake.split(self.solution) u_old, p_old = self.solution_old.split() u_theta = (1-self.theta)*u_old + self.theta*u p_theta = (1-self.theta)*p_old + self.theta*p z_theta = [u_theta, p_theta] self._fields = [] for i, cpl in enumerate(self.coupling): cfields = self.fields.copy() for field_name, eqno in cpl.items(): assert 0 <= eqno <= 2 and not eqno == i cfields[field_name] = z_theta[eqno] self._fields.append(cfields) self.F = self.equations[0].mass_term(self.test[0], u-u_old) self.F -= self.dt_const * self.equations[0].residual(self.test[0], u_theta, u_old, self._fields[0], bcs=self.bcs) # linearise using u_old self.F -= self.dt_const*self.equations[1].residual(self.test[1], p_theta, p_theta, self._fields[1], bcs=self.bcs) self.problem = firedrake.NonlinearVariationalProblem(self.F, self.solution, self.strong_bcs) self.solver = firedrake.NonlinearVariationalSolver(self.problem, solver_parameters=self.solver_parameters, options_prefix=self.name) self._initialized = True
def initialize(self, init_solution): self.solution_old.assign(init_solution) z_theta = (1-self.theta)*self.solution_old + self.theta*self.solution self._fields = [] for fields in self.fields: cfields = fields.copy() for field_name, field_expr in fields.items(): if isinstance(field_expr, float): continue cfields[field_name] = firedrake.replace(field_expr, {self.solution: z_theta}) self._fields.append(cfields) F = 0 for test, u, u_old, eq, mass_term, fields, bcs in zip(self.test, firedrake.split(self.solution), firedrake.split(self.solution_old), self.equations, self.mass_terms, self._fields, self.bcs): if mass_term: F += eq.mass_term(test, u-u_old) u_theta = (1-self.theta)*u_old + self.theta*u F -= self.dt_const * eq.residual(test, u_theta, u_theta, fields, bcs=bcs) self.problem = firedrake.NonlinearVariationalProblem(F, self.solution, bcs=self.strong_bcs) self.solver = firedrake.NonlinearVariationalSolver(self.problem, solver_parameters=self.solver_parameters, options_prefix=self.name) self._initialized = True
def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: self._fields[name] = utilities.copy(field) # 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 solve( self, parameters={ "snes_type": "newtonls", "snes_monitor": True, "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "pc_factor_mat_solver_type": "mumps" }): problem = fe.NonlinearVariationalProblem( F=self.variational_form_residual, u=self.solution, bcs=self.dirichlet_boundary_conditions, J=fe.derivative(self.variational_form_residual, self.solution)) solver = fe.NonlinearVariationalSolver(problem=problem, solver_parameters=parameters) solver.solve() self.snes_iteration_count += solver.snes.getIterationNumber() return self.solution
def __init__(self, mesh_m): super().__init__() self.mesh_m = 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)
def _setup(self, **kwargs): 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 = Constant(1.) aflux = self.model.advective_flux(**self.fields) dflux = self.model.diffusive_flux(**self.fields) sources = self.model.sources(**self.fields) dE_dt = sources - aflux - dflux E = self.fields.get('energy', self.fields.get('E')) h = self.fields.get('thickness', self.fields.get('h')) E_0 = E.copy(deepcopy=True) ψ = firedrake.TestFunction(E.function_space()) F = (E - E_0) * ψ * h * dx - dt * dE_dt degree = E.ufl_element().degree() fc_params = {'quadrature_degree': (3 * degree[0], 2 * degree[1])} problem = firedrake.NonlinearVariationalProblem( F, E, form_compiler_parameters=fc_params ) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters ) self._energy_old = E_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 %s field has type %s, must be Constant or Function!" % (name, type(field))) dt = Constant(1.0) aflux = self.model.advective_flux(**self.fields) dflux = self.model.diffusive_flux(**self.fields) sources = self.model.sources(**self.fields) dE_dt = sources - aflux - dflux E, h = itemgetter("energy", "thickness")(self.fields) E_0 = E.copy(deepcopy=True) ψ = firedrake.TestFunction(E.function_space()) F = (E - E_0) * ψ * h * dx - dt * dE_dt degree = E.ufl_element().degree() fc_params = {"quadrature_degree": (3 * degree[0], 2 * degree[1])} problem = firedrake.NonlinearVariationalProblem( F, E, form_compiler_parameters=fc_params) self._solver = firedrake.NonlinearVariationalSolver( problem, solver_parameters=self._solver_parameters) self._energy_old = E_0 self._timestep = dt
def __init__(self, problem: fd.NonlinearVariationalProblem, **kwargs) -> None: """Same than NonlinearVariationalSolver, but with just the SIMPLE preconditioner by default Args: problem ([type]): [description] nullspace ([type], optional): [description]. Defaults to None. solver_parameters ([type], optional): [description]. Defaults to None. """ solver_parameters_default = { # "snes_type": "ksponly", # "snes_no_convergence_test" : None, # "snes_max_it": 1, "snes_type": "newtonls", "snes_linesearch_type": "l2", "snes_linesearch_maxstep": 1.0, # "snes_monitor": None, # "snes_linesearch_monitor": None, "snes_rtol": 1.0e-4, "snes_atol": 1.0e-4, "snes_stol": 0.0, "snes_max_linear_solve_fail": 10, "snes_converged_reason": None, "ksp_type": "fgmres", "mat_type": "aij", # "default_sub_matrix_type": "aij", "ksp_rtol": 1.0e-4, "ksp_atol": 1.0e-4, "ksp_max_it": 2000, # "ksp_monitor": None, "ksp_converged_reason": None, "pc_type": "fieldsplit", "pc_fieldsplit_type": "schur", "pc_fieldsplit_schur_factorization_type": "full", "pc_fieldsplit_schur_precondition": "selfp", "fieldsplit_0": { "ksp_type": "richardson", "ksp_richardson_self_scale": False, "ksp_max_it": 1, "pc_type": "ml", "ksp_atol": 1e-2, "pc_mg_cycle_type": "v", "pc_mg_type": "full", # "ksp_converged_reason": None, # "ksp_monitor": None, }, "fieldsplit_1": { "ksp_type": "preonly", "pc_type": "ml", # "ksp_monitor": None, # "ksp_converged_reason": None, }, "fieldsplit_1_upper_ksp_type": "preonly", "fieldsplit_1_upper_pc_type": "jacobi", } solver_parameters = kwargs.pop("solver_parameters", None) if solver_parameters: solver_parameters_default.update(solver_parameters) self.solver = fd.NonlinearVariationalSolver( problem, solver_parameters=solver_parameters_default, **kwargs)
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 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 __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
"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" } } solver = fd.NonlinearVariationalSolver(problem, solver_parameters=hybrid_solver_params) # ----------------- wave_speed = fd.conditional(fd.lt(np.abs(vnorm), tol), h / tol, h / vnorm) # CFL dt_ = fd.interpolate(wave_speed, DG1).dat.data.min() * cfl outfile = fd.File(f"plots/adr-hdg-n-{refine}-p-{order}.pvd", project_output=True) dt = dt_ # dtime dtc.assign(dt_) # %% # solve problem # initialize timestep t = 0.0
# 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( fd.interpolate(Pe, DG0).dat.data.mean(), dt))
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)
# 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: t += dt
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 __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)
# 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") w0.sub(2).assign(0.0) # initialize timestep t = 0.0 it = 0 dt = np.sqrt(tol)
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()[:]))
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 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 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