def get_facet_areas(mesh): """ Compute area of each facet of `mesh`. The facet areas are stored as a HDiv trace field. Note that the plus sign is arbitrary and could equally well be chosen as minus. :arg mesh: the input mesh to do computations on :rtype: firedrake.function.Function facet_areas with facet area data """ HDivTrace = firedrake.FunctionSpace(mesh, "HDiv Trace", 0) v = firedrake.TestFunction(HDivTrace) u = firedrake.TrialFunction(HDivTrace) facet_areas = firedrake.Function(HDivTrace, name="Facet areas") mass_term = v("+") * u("+") * ufl.dS + v * u * ufl.ds rhs = v("+") * ufl.FacetArea(mesh) * ufl.dS + v * ufl.FacetArea(mesh) * ufl.ds sp = { "snes_type": "ksponly", "ksp_type": "preonly", "pc_type": "jacobi", } firedrake.solve(mass_term == rhs, facet_areas, solver_parameters=sp) return facet_areas
def compressible_eady_initial_v(state, theta0, rho0, v): f = state.parameters.f cp = state.parameters.cp # exner function Vr = rho0.function_space() Pi = Function(Vr).interpolate(thermodynamics.pi(state.parameters, rho0, theta0)) # get Pi gradient Vu = state.spaces("HDiv") g = TrialFunction(Vu) wg = TestFunction(Vu) n = FacetNormal(state.mesh) a = inner(wg, g)*dx L = -div(wg)*Pi*dx + inner(wg, n)*Pi*ds_tb pgrad = Function(Vu) solve(a == L, pgrad) # get initial v m = TrialFunction(Vr) phi = TestFunction(Vr) a = phi*f*m*dx L = phi*cp*theta0*pgrad[0]*dx solve(a == L, v) return v
def _newton_solve(z, E, scale, tolerance=1e-6, armijo=1e-4, max_iterations=50): F = derivative(E, z) H = derivative(F, z) Q = z.function_space() bc = firedrake.DirichletBC(Q, 0, 'on_boundary') p = firedrake.Function(Q) for iteration in range(max_iterations): firedrake.solve(H == -F, p, bc, solver_parameters={'ksp_type': 'preonly', 'pc_type': 'lu'}) dE_dp = assemble(action(F, p)) α = 1.0 E0 = assemble(E) Ez = assemble(replace(E, {z: z + firedrake.Constant(α) * p})) while (Ez > E0 + armijo * α * dE_dp) or np.isnan(Ez): α /= 2 Ez = assemble(replace(E, {z: z + firedrake.Constant(α) * p})) z.assign(z + firedrake.Constant(α) * p) if abs(dE_dp) < tolerance * assemble(scale): return z raise ValueError("Newton solver failed to converge after {0} iterations" .format(max_iterations))
def test_LinearSolver_solve_prior_generating(fs, A, b, fc, od, params, interp, A_numpy, cov, K, ls): "test the function to solve the prior of the generating process" ls.set_params(params) m_eta, C_eta = ls.solve_prior_generating() m_eta2, C_eta2 = solve_prior_generating(A, b, fc, od, params) rho = np.exp(params[0]) C_expected = np.linalg.solve(A_numpy, interp) C_expected = np.dot(cov, C_expected) C_expected = np.linalg.solve(A_numpy, C_expected) C_expected = rho**2 * np.dot(interp.T, C_expected) + K u = Function(fs) solve(A, u, b) m_expected = rho * np.dot(interp.T, u.vector().gather()) if COMM_WORLD.rank == 0: assert_allclose(m_expected, m_eta, atol=1.e-10) assert_allclose(C_expected, C_eta, atol=1.e-10) assert_allclose(m_expected, m_eta2, atol=1.e-10) assert_allclose(C_expected, C_eta2, atol=1.e-10) else: assert m_eta.shape == (0, ) assert C_eta.shape == (0, 0) assert m_eta2.shape == (0, ) assert C_eta2.shape == (0, 0) fc.destroy()
def gauss_newton_energy_norm(self, q): r"""Compute the energy norm of a field w.r.t. the Gauss-Newton operator The energy norm of a field :math:`q` w.r.t. the Gauss-Newton operator :math:`H` can be computed using one fewer linear solve than if we were to calculate the action of :math:`H\cdot q` on :math:`q`. This saves computation when using the conjugate gradient method to solve for the search direction. """ u, p = self.state, self.parameter dE = derivative(self._E, u) dR = derivative(self._R, p) dF_du, dF_dp = self._dF_du, derivative(self._F, p) v = firedrake.Function(u.function_space()) firedrake.solve(dF_du == action(dF_dp, q), v, self._bc, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params) return self._assemble( firedrake.energy_norm(derivative(dE, u), v) + firedrake.energy_norm(derivative(dR, p), q))
def test_LinearSolver_solve_prior(fs, A, b, fc, od, interp, cov, A_numpy, ls): "test solve_conditioned_FEM" mu, Cu = ls.solve_prior() mu2, Cu2 = solve_prior(A, b, fc, od) C_expected = np.linalg.solve(A_numpy, interp) C_expected = np.dot(cov, C_expected) C_expected = np.linalg.solve(A_numpy, C_expected) C_expected = np.dot(interp.T, C_expected) u = Function(fs) solve(A, u, b) m_expected = np.dot(interp.T, u.vector().gather()) if COMM_WORLD.rank == 0: assert_allclose(m_expected, mu, atol=1.e-10) assert_allclose(C_expected, Cu, atol=1.e-10) assert_allclose(m_expected, mu2, atol=1.e-10) assert_allclose(C_expected, Cu2, atol=1.e-10) else: assert mu.shape == (0, ) assert Cu.shape == (0, 0) assert mu2.shape == (0, ) assert Cu2.shape == (0, 0) fc.destroy()
def _ad_convert_type(self, value, options=None): from firedrake import Function, TrialFunction, TestFunction, assemble options = {} if options is None else options riesz_representation = options.get("riesz_representation", "l2") if riesz_representation == "l2": return Function(self.function_space(), val=value) elif riesz_representation == "L2": ret = Function(self.function_space()) u = TrialFunction(self.function_space()) v = TestFunction(self.function_space()) M = assemble(firedrake.inner(u, v) * firedrake.dx) firedrake.solve(M, ret, value) return ret elif riesz_representation == "H1": ret = Function(self.function_space()) u = TrialFunction(self.function_space()) v = TestFunction(self.function_space()) M = assemble( firedrake.inner(u, v) * firedrake.dx + firedrake.inner(firedrake.grad(u), firedrake.grad(v)) * firedrake.dx) firedrake.solve(M, ret, value) return ret elif callable(riesz_representation): return riesz_representation(value) else: raise NotImplementedError("Unknown Riesz representation %s" % riesz_representation)
def eady_initial_v(state, p0, v): f = state.parameters.f x, y, z = SpatialCoordinate(state.mesh) # get pressure gradient Vu = state.spaces("HDiv") g = TrialFunction(Vu) wg = TestFunction(Vu) n = FacetNormal(state.mesh) a = inner(wg, g)*dx L = -div(wg)*p0*dx + inner(wg, n)*p0*ds_tb pgrad = Function(Vu) solve(a == L, pgrad) # get initial v Vp = p0.function_space() phi = TestFunction(Vp) m = TrialFunction(Vp) a = f*phi*m*dx L = phi*pgrad[0]*dx solve(a == L, v) return v
def _advect(self, dt, E, u, w, h, s, E_inflow, E_surface): Q = E.function_space() φ, ψ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q) U = firedrake.as_vector((u[0], u[1], w)) flux_cells = -φ * inner(U, grad(ψ)) * h * dx mesh = Q.mesh() ν = facet_normal_2(mesh) outflow = firedrake.max_value(inner(u, ν), 0) inflow = firedrake.min_value(inner(u, ν), 0) flux_outflow = φ * ψ * outflow * h * ds_v + \ φ * ψ * firedrake.max_value(-w, 0) * h * ds_b + \ φ * ψ * firedrake.max_value(+w, 0) * h * ds_t F = φ * ψ * h * dx + dt * (flux_cells + flux_outflow) flux_inflow = -E_inflow * ψ * inflow * h * ds_v \ -E_surface * ψ * firedrake.min_value(-w, 0) * h * ds_b \ -E_surface * ψ * firedrake.min_value(+w, 0) * h * ds_t A = E * ψ * h * dx + dt * flux_inflow solver_parameters = {'ksp_type': 'preonly', 'pc_type': 'lu'} degree_E = E.ufl_element().degree() degree_u = u.ufl_element().degree() degree = (3 * degree_E[0] + degree_u[0], 2 * degree_E[1] + degree_u[1]) form_compiler_parameters = {'quadrature_degree': degree} firedrake.solve(F == A, E, solver_parameters=solver_parameters, form_compiler_parameters=form_compiler_parameters)
def solve(self): super().solve() # self.solver.solve() fd.solve(self.F == 0, self.solution, bcs=self.bcs, solver_parameters=self.params, nullspace=self.nsp)
def solve_something(mesh): V = fd.FunctionSpace(mesh, "CG", 1) u = fd.Function(V) v = fd.TestFunction(V) x, y = fd.SpatialCoordinate(mesh) # f = fd.sin(x) * fd.sin(y) + x**2 + y**2 # uex = x**4 * y**4 uex = fd.sin(x) * fd.sin(y) #*(x*y)**3 # def source(xs, ys): # return 1/((x-xs)**2+(y-ys)**2 + 0.1) # uex = source(0, 0) uex = uex - fd.assemble(uex * fd.dx) / fd.assemble(1 * fd.dx(domain=mesh)) # f = fd.conditional(fd.ge(abs(x)-abs(y), 0), 1, 0) from firedrake import inner, grad, dx, ds, div, sym eps = fd.Constant(0.0) f = uex - div(grad(uex)) + eps * div(grad(div(grad(uex)))) n = fd.FacetNormal(mesh) g = inner(grad(uex), n) g1 = inner(grad(div(grad(uex))), n) g2 = div(grad(uex)) # F = 0.1 * inner(u, v) * dx + inner(grad(u), grad(v)) * dx + inner(grad(grad(u)), grad(grad(v))) * dx - f * v * dx - g * v * ds F = inner(u, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx - g * v * ds F += eps * inner(div(grad(u)), div(grad(v))) * dx F += eps * g1 * v * ds F -= eps * g2 * inner(grad(v), n) * ds # f = -div(grad(uex)) # F = inner(grad(u), grad(v)) * dx - f * v * dx # bc = fd.DirichletBC(V, uex, "on_boundary") bc = None fd.solve(F == 0, u, bcs=bc, solver_parameters={ "ksp_type": "cg", "ksp_atol": 1e-13, "ksp_rtol": 1e-13, "ksp_dtol": 1e-13, "ksp_stol": 1e-13, "pc_type": "jacobi", "pc_factor_mat_solver_type": "mumps", "snes_type": "ksponly", "ksp_converged_reason": None }) print("||u-uex|| =", fd.norm(u - uex)) print("||grad(u-uex)|| =", fd.norm(grad(u - uex))) print("||grad(grad(u-uex))|| =", fd.norm(grad(grad(u - uex)))) err = fd.Function( fd.TensorFunctionSpace(mesh, "DG", V.ufl_element().degree() - 2)).interpolate( grad(grad(u - uex))) # err = fd.Function(fd.FunctionSpace(mesh, "DG", V.ufl_element().degree())).interpolate(u-uex) fd.File(outdir + "sln.pvd").write(u) fd.File(outdir + "err.pvd").write(err)
def incompressible_hydrostatic_balance(state, b0, p0, top=False, params=None): # get F Vu = state.spaces("HDiv") Vv = FunctionSpace(state.mesh, Vu.ufl_element()._elements[-1]) v = TrialFunction(Vv) w = TestFunction(Vv) if top: bstring = "top" else: bstring = "bottom" bcs = [DirichletBC(Vv, 0.0, bstring)] a = inner(w, v) * dx L = inner(state.k, w) * b0 * dx F = Function(Vv) solve(a == L, F, bcs=bcs) # define mixed function space VDG = state.spaces("DG") WV = (Vv) * (VDG) # get pprime v, pprime = TrialFunctions(WV) w, phi = TestFunctions(WV) bcs = [DirichletBC(WV[0], zero(), bstring)] a = (inner(w, v) + div(w) * pprime + div(v) * phi) * dx L = phi * div(F) * dx w1 = Function(WV) if params is None: params = { 'ksp_type': 'gmres', 'pc_type': 'fieldsplit', 'pc_fieldsplit_type': 'schur', 'pc_fieldsplit_schur_fact_type': 'full', 'pc_fieldsplit_schur_precondition': 'selfp', 'fieldsplit_1_ksp_type': 'preonly', 'fieldsplit_1_pc_type': 'gamg', 'fieldsplit_1_mg_levels_pc_type': 'bjacobi', 'fieldsplit_1_mg_levels_sub_pc_type': 'ilu', 'fieldsplit_0_ksp_type': 'richardson', 'fieldsplit_0_ksp_max_it': 4, 'ksp_atol': 1.e-08, 'ksp_rtol': 1.e-08 } solve(a == L, w1, bcs=bcs, solver_parameters=params) v, pprime = w1.split() p0.project(pprime)
def update_search_direction(self): r"""Set the search direction to be the inverse of the mass matrix times the gradient of the objective""" q, dJ = self.search_direction, self.gradient Q = q.function_space() M = firedrake.TrialFunction(Q) * firedrake.TestFunction(Q) * dx firedrake.solve(M == -dJ, q, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params)
def update_adjoint_state(self): r"""Update the adjoint state for new values of the observable state and parameters so that we can calculate derivatives""" λ = self.adjoint_state L = adjoint(self._dF_du) firedrake.solve(L == -self._dE, λ, self._bc, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params)
def solvevdisp(mesh,bdryids,deltah): P1 = FunctionSpace(mesh, "CG", 1) r = TrialFunction(P1) s = TestFunction(P1) a = inner(grad(r), grad(s)) * dx # note natural b.c. on outflow L = inner(Constant(0.0), s) * dx # WARNING: top must go *first* so closed top gets zero; is this documented behavior? bcs = [ DirichletBC(P1, deltah, bdryids['top']), DirichletBC(P1, Constant(0.0), (bdryids['base'],bdryids['inflow'])) ] rsoln = Function(P1) solve(a == L, rsoln, bcs=bcs, options_prefix='vd', solver_parameters={}) return rsoln
def solve(self): super().solve() self.failed_to_solve = False u_old = self.solution.copy(deepcopy=True) try: fd.solve(self.F == 0, self.solution, bcs=self.bcs, solver_parameters=self.params) except fd.ConvergenceError: self.failed_to_solve = True self.solution.assign(u_old)
def solve(self, dt, h0, a, u, h_inflow=None): r"""Propagate the thickness forward by one timestep This function uses the implicit Euler timestepping scheme to avoid the stability issues associated to using continuous finite elements for advection-type equations. The implicit Euler scheme is stable for any timestep; you do not need to ensure that the CFL condition is satisfied in order to get an answer. Nonetheless, keeping the timestep within the CFL bound is a good idea for accuracy. Parameters ---------- dt : float Timestep h0 : firedrake.Function Initial ice thickness a : firedrake.Function Sum of accumulation and melt rates u : firedrake.Function Ice velocity h_inflow : firedrake.Function Thickness of the upstream ice that advects into the domain Returns ------- h : firedrake.Function Ice thickness at `t + dt` """ grad, ds = self.grad, self.ds h_inflow = h_inflow if h_inflow is not None else h0 Q = h0.function_space() h, φ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q) n = self.facet_normal(Q.mesh()) outflow = firedrake.max_value(inner(u, n), 0) inflow = firedrake.min_value(inner(u, n), 0) flux_cells = -h * inner(u, grad(φ)) * dx flux_out = h * φ * outflow * ds F = h * φ * dx + dt * (flux_cells + flux_out) accumulation = a * φ * dx flux_in = -h_inflow * φ * inflow * ds A = h0 * φ * dx + dt * (accumulation + flux_in) h = h0.copy(deepcopy=True) solver_parameters = {'ksp_type': 'preonly', 'pc_type': 'lu'} firedrake.solve(F == A, h, solver_parameters=solver_parameters) return h
def solvePDE(self): """Solve the heat equation and evaluate the objective function.""" self.J = 0 t = 0 self.u.assign(self.u0) self.J += fd.assemble(self.dt * (self.u - self.u_t(t))**2 * self.dx) for ii in range(10): self.u_old.assign(self.u) fd.solve(self.F(t, self.u, self.u_old) == 0, self.u, bcs=self.bcs) t += self.dt self.J += fd.assemble(self.dt * (self.u - self.u_t(t))**2 * self.dx)
def solve(self, dt, h0, a, u, h_inflow=None): r"""Propagate the thickness forward by one timestep This function uses an implicit second-order Taylor-Galerkin (also known as Lax-Wendroff) scheme to solve the conservative advection equation for ice thickness. Parameters ---------- dt : float Timestep h0 : firedrake.Function Initial ice thickness a : firedrake.Function Sum of accumulation and melt rates u : firedrake.Function Ice velocity h_inflow : firedrake.Function Thickness of the upstream ice that advects into the domain Returns ------- h : firedrake.Function Ice thickness at `t + dt` """ grad, div, ds = self.grad, self.div, self.ds h_inflow = h_inflow if h_inflow is not None else h0 Q = h0.function_space() h, φ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q) n = self.facet_normal(Q.mesh()) outflow = firedrake.max_value(inner(u, n), 0) inflow = firedrake.min_value(inner(u, n), 0) flux_cells = -h * inner(u, grad(φ)) * dx flux_cells_lax = 0.5 * dt * div(h * u) * inner(u, grad(φ)) * dx flux_out = (h - 0.5 * dt * div(h * u)) * φ * outflow * ds F = h * φ * dx + dt * (flux_cells + flux_cells_lax + flux_out) accumulation = a * φ * dx flux_in = -(h_inflow - 0.5 * dt * div(h0 * u)) * φ * inflow * ds A = h0 * φ * dx + dt * (accumulation + flux_in) h = h0.copy(deepcopy=True) solver_parameters = {'ksp_type': 'preonly', 'pc_type': 'lu'} firedrake.solve(F == A, h, solver_parameters=solver_parameters) return h
def solve(self, q, f, dirichlet_ids=[], **kwargs): u = firedrake.Function(f.function_space()) L = self.action(q, u, f) F = firedrake.derivative(L, u) V = u.function_space() bc = firedrake.DirichletBC(V, firedrake.Constant(0), dirichlet_ids) firedrake.solve(F == 0, u, bc, solver_parameters={ 'ksp_type': 'preonly', 'pc_type': 'lu' }) return u
def update_search_direction(self): r"""Solve the Gauss-Newton system for the new search direction using the preconditioned conjugate gradient method""" p, q, dJ = self.parameter, self.search_direction, self.gradient dR = derivative(self.regularization, self.parameter) Q = q.function_space() M = firedrake.TrialFunction(Q) * firedrake.TestFunction(Q) * dx + \ derivative(dR, p) # Compute the preconditioned residual z = firedrake.Function(Q) firedrake.solve(M == -dJ, z, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params) # This variable is a search direction for a search direction, which # is definitely not confusing at all. s = z.copy(deepcopy=True) q *= 0.0 old_cost = np.inf while True: z_mnorm = self._assemble(firedrake.energy_norm(M, z)) s_hnorm = self.gauss_newton_energy_norm(s) α = z_mnorm / s_hnorm δz = firedrake.Function(Q) g = self.gauss_newton_mult(s) firedrake.solve(M == g, δz, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params) q += α * s z -= α * δz β = self._assemble(firedrake.energy_norm(M, z)) / z_mnorm s *= β s += z energy_norm = self.gauss_newton_energy_norm(q) cost = 0.5 * energy_norm + self._assemble(action(dJ, q)) if (abs(old_cost - cost) / (0.5 * energy_norm) < self._search_tolerance): return old_cost = cost
def solve_firedrake(q, kappa0, kappa1): x = firedrake.SpatialCoordinate(mesh) f = x[0] u = firedrake.Function(V) bcs = [firedrake.DirichletBC(V, firedrake.Constant(0.0), "on_boundary")] inner, grad, dx = ufl.inner, ufl.grad, ufl.dx JJ = 0.5 * inner(kappa0 * grad(u), grad(u)) * dx - q * kappa1 * f * u * dx v = firedrake.TestFunction(V) F = firedrake.derivative(JJ, u, v) firedrake.solve(F == 0, u, bcs=bcs) return u
def step(self, dt): self.dt.assign(dt) try: # Solve for potential firedrake.solve( self.F == 0, self.model.phi, self.model.d_bcs, J=self.J, solver_parameters={ "snes_monitor": None, "snes_view": None, "ksp_monitor_true_residual": None, "snes_converged_reason": None, "ksp_converged_reason": None, }, ) # , solver_parameters = self.model.newton_params) # Derive values from the new potential self.model.update_phi() except: # Try the solve again with a lower relaxation param firedrake.solve( self.F == 0, self.model.phi, self.model.d_bcs, J=self.J, solver_parameters={ "snes_type": "newtonls", "snes_rtol": 5e-11, "snes_atol": 5e-10, "pc_type": "lu", "snes_max_it": 50, "mat_type": "aij", }, ) # , solver_parameters = self.model.newton_params) # Derive values from potential self.model.update_phi() # Didn't converge with standard params return False # Did converge with standard params return True
def distance_function(mesh, boundary_ids="on_boundary", order=1, eps=fd.Constant(0.1)): V = fd.FunctionSpace(mesh, "CG", order) u = fd.Function(V) v = fd.TestFunction(V) a = eps * fd.inner(fd.grad(u), fd.grad(v)) * fd.dx \ + fd.inner(fd.grad(u), fd.grad(u)) * v * fd.dx \ - v * fd.dx fd.solve(a == 0, u, bcs=fd.DirichletBC(V, 0, boundary_ids)) return u def get_nullspace(self, V): return self.inner.get_nullspace(V)
def form2indicator(F): """ Multiply throughout in a form and assemble as a cellwise error indicator. :arg F: the form """ mesh = F.ufl_domain() P0 = firedrake.FunctionSpace(mesh, "DG", 0) p0test = firedrake.TestFunction(P0) indicator = firedrake.Function(P0) # Contributions from surface integrals flux_terms = 0 integrals = F.integrals_by_type("exterior_facet") if len(integrals) > 0: for integral in integrals: ds = firedrake.ds(integral.subdomain_id()) flux_terms += p0test * integral.integrand() * ds integrals = F.integrals_by_type("interior_facet") if len(integrals) > 0: for integral in integrals: dS = firedrake.dS(integral.subdomain_id()) flux_terms += p0test("+") * integral.integrand() * dS flux_terms += p0test("-") * integral.integrand() * dS if flux_terms != 0: dx = firedrake.dx mass_term = firedrake.TrialFunction(P0) * p0test * dx sp = { "snes_type": "ksponly", "ksp_type": "preonly", "pc_type": "jacobi", } firedrake.solve(mass_term == flux_terms, indicator, solver_parameters=sp) # Contributions from volume integrals cell_terms = 0 integrals = F.integrals_by_type("cell") if len(integrals) > 0: for integral in integrals: dx = firedrake.dx(integral.subdomain_id()) cell_terms += p0test * integral.integrand() * dx indicator += firedrake.assemble(cell_terms) return indicator
def get_mu(self, V): W = fd.FunctionSpace(V.mesh(), "CG", 1) bcs = [] if len(self.fixed_bids): bcs.append(fd.DirichletBC(W, 1, self.fixed_bids)) if len(self.free_bids): bcs.append(fd.DirichletBC(W, 10, self.free_bids)) if len(bcs) == 0: bcs = None u = fd.TrialFunction(W) v = fd.TestFunction(W) a = fd.inner(fd.grad(u), fd.grad(v)) * fd.dx b = fd.inner(fd.Constant(0.), v) * fd.dx mu = fd.Function(W) fd.solve(a == b, mu, bcs=bcs) return mu
def eval_ddJdw(self): u = self.u v = self.v J = self.J F = self.F X = self.X w = self.w V = self.V L = self.L bil_form = self.bil_form params = self.params s = w y_s = Function(V) # follow p 65 of Hinze, Pinnau, Ulbrich, Ulbrich # Step 1: solve( assemble(derivative(F, u)), y_s, assemble(derivative(-F, X, s)), solver_parameters=params, bcs=self.bc, ) # Step 2: Lyy_y_s = assemble(derivative(derivative(L, u), u, y_s)) Lyu_s = assemble(derivative(derivative(L, u), X, s)) h1 = Lyy_y_s h1 += Lyu_s Luy_y_s = assemble(derivative(derivative(L, X), u, y_s)) Luu_s = assemble(derivative(derivative(L, X), X, s)) h2 = Luy_y_s h2 += Luu_s h3_temp = Function(V) # Step 3: solve(assemble(bil_form), h3_temp, h1, bcs=self.bc, solver_parameters=params) F_h3_temp = replace(F, {v: h3_temp}) h3 = assemble(derivative(-F_h3_temp, X)) res = h2 res += h3 return res.vector().inner(w.vector())
def solve(self, velocity, dJ): """Solve the problem Args: velocity ([type]): Solution. velocity means regularized shape derivatives dJ ([type]): Shape derivatives to be regularized """ for bc in self.bcs: bc.apply(dJ) solve( self.Av, velocity.vector(), dJ, options_prefix="reg_solver", solver_parameters=self.solver_parameters, )
def _diffuse(self, dt, E, h, q, q_bed, E_surface): Q = E.function_space() degree = Q.ufl_element().degree()[1] φ, ψ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q) a = (h * φ * ψ + dt * α * φ.dx(2) * ψ.dx(2) / h) * dx \ + degree**2 * dt * α * φ * ψ / h * ds_t f = E * ψ * h * dx \ + dt * q * ψ * h * dx \ + dt * q_bed * ψ * ds_b \ + degree**2 * dt * α * E_surface * ψ / h * ds_t degree_E = E.ufl_element().degree() degree = (3 * degree_E[0], 2 * degree_E[1]) form_compiler_parameters = {'quadrature_degree': degree} firedrake.solve(a == f, E, form_compiler_parameters=form_compiler_parameters)
def update_search_direction(self): r"""Apply the low-rank approximation of the Hessian inverse This procedure implements the two-loop recursion algorithm to apply the low-rank approximation of the Hessian inverse to the derivative of the objective functional. See Nocedal and Wright, Numerical Optimization, 2nd ed., algorithm 7.4.""" p, q, dJ = self.parameter, self.search_direction, self.gradient Q = q.function_space() M = firedrake.TrialFunction(Q) * firedrake.TestFunction(Q) * dx f = firedrake.Function(Q) firedrake.solve(M == dJ, f, solver_parameters=self._solver_params, form_compiler_parameters=self._fc_params) # Append the latest values of the parameters and the objective gradient # and compute the curvature factor ps, fs, ρ = self._ps, self._fs, self._rho ρ.append(1 / self._assemble((p - ps[-1]) * (f - fs[-1]) * dx)) ps.append(p.copy(deepcopy=True)) fs.append(f.copy(deepcopy=True)) # Forget any old values of the parameters and objective gradient ps = ps[-(self.memory + 1):] fs = fs[-(self.memory + 1):] ρ = ρ[-self.memory:] g = f.copy(deepcopy=True) m = len(ρ) α = np.zeros(m) for i in range(m - 1, -1, -1): α[i] = ρ[i] * self._assemble(f * (ps[i + 1] - ps[i]) * dx) g -= α[i] * (fs[i + 1] - fs[i]) r = g.copy(deepcopy=True) dp, df = ps[-1] - ps[-2], fs[-1] - fs[-2] r *= self._assemble(dp * df * dx) / self._assemble(df * df * dx) for i in range(m): β = ρ[i] * self._assemble((fs[i + 1] - fs[i]) * r * dx) r += (α[i] - β) * (ps[i + 1] - ps[i]) q.assign(-r)
def compute_space_accuracy_via_mms( grid_sizes, element_degree, quadrature_degree, smoothing): dx = fe.dx(degree = quadrature_degree) parameters["smoothing"].assign(smoothing) h, e, order = [], [], [] for gridsize in grid_sizes: mesh = fe.UnitIntervalMesh(gridsize) element = fe.FiniteElement("P", mesh.ufl_cell(), element_degree) V = fe.FunctionSpace(mesh, element) u_m = manufactured_solution(mesh) bc = fe.DirichletBC(V, u_m, "on_boundary") u = fe.TrialFunction(V) v = fe.TestFunction(V) u_h = fe.Function(V) fe.solve(F(u, v)*dx == v*R(u_m)*dx, u_h, bcs = bc) e.append(math.sqrt(fe.assemble(fe.inner(u_h - u_m, u_h - u_m)*dx))) h.append(1./float(gridsize)) if len(e) > 1: r = h[-2]/h[-1] log = math.log order = log(e[-2]/e[-1])/log(r) print("{0: <4}, {1: .3f}, {2: .5f}, {3: .3f}, {4: .3f}".format( str(quadrature_degree), smoothing, h[-1], e[-1], order))
def __init__(self, mesh, vertical_degree=1, horizontal_degree=1, family="RT", z=None, k=None, Omega=None, mu=None, timestepping=None, output=None, parameters=None, diagnostics=None, fieldlist=None, diagnostic_fields=[], on_sphere=False): super(BaroclinicState, self).__init__(mesh=mesh, vertical_degree=vertical_degree, horizontal_degree=horizontal_degree, family=family, z=z, k=k, Omega=Omega, mu=mu, timestepping=timestepping, output=output, parameters=parameters, diagnostics=diagnostics, fieldlist=fieldlist, diagnostic_fields=diagnostic_fields) # build the geopotential if parameters.geopotential: V = FunctionSpace(mesh, "CG", 1) if on_sphere: self.Phi = Function(V).interpolate(Expression("pow(x[0]*x[0]+x[1]*x[1]+x[2]*x[2],0.5)")) else: self.Phi = Function(V).interpolate(Expression("x[1]")) self.Phi *= parameters.g if self.k is None: # build the vertical normal w = TestFunction(self.Vv) u = TrialFunction(self.Vv) self.k = Function(self.Vv) n = FacetNormal(self.mesh) krhs = -div(w)*self.z*dx + inner(w,n)*self.z*ds_tb klhs = inner(w,u)*dx solve(klhs == krhs, self.k)