def AdvectionDiffusionGLS( V: fd.FunctionSpace, theta: fd.Function, phi: fd.Function, PeInv: float = 1e-4, phi_t: fd.Function = None, ): PeInv_ct = fd.Constant(PeInv) rho = fd.TestFunction(V) F = (inner(theta, grad(phi)) * rho + PeInv_ct * inner(grad(phi), grad(rho))) * dx if phi_t: F += phi_t * rho * dx h = fd.CellDiameter(V.ufl_domain()) R_U = dot(theta, grad(phi)) - PeInv_ct * div(grad(phi)) if phi_t: R_U += phi_t beta_gls = 0.9 tau_gls = beta_gls * ((4.0 * dot(theta, theta) / h**2) + 9.0 * (4.0 * PeInv_ct / h**2)**2)**(-0.5) theta_U = dot(theta, grad(rho)) - PeInv_ct * div(grad(rho)) F += tau_gls * inner(R_U, theta_U) * dx() return F
def residual(self, test, trial, trial_lagged, fields, bcs): u_adv = trial_lagged phi = test n = self.n u = trial F = -dot(u, div(outer(phi, u_adv)))*self.dx for id, bc in bcs.items(): if 'u' in bc: u_in = bc['u'] elif 'un' in bc: u_in = bc['un'] * n # this implies u_t=0 on the inflow else: u_in = zero(self.dim) F += conditional(dot(u_adv, n) < 0, dot(phi, u_in)*dot(u_adv, n), dot(phi, u)*dot(u_adv, n)) * self.ds(id) if not (is_continuous(self.trial_space) and normal_is_continuous(u_adv)): # s=0: u.n(-)<0 => flow goes from '+' to '-' => '+' is upwind # s=1: u.n(-)>0 => flow goes from '-' to '+' => '-' is upwind s = 0.5*(sign(dot(avg(u), n('-'))) + 1.0) u_up = u('-')*s + u('+')*(1-s) F += dot(u_up, (dot(u_adv('+'), n('+'))*phi('+') + dot(u_adv('-'), n('-'))*phi('-'))) * self.dS return -F
def __init__(self, state, linear=False): self.state = state g = state.parameters.g f = state.f Vu = state.V[0] W = state.W self.x0 = Function(W) # copy x to here u0, D0 = split(self.x0) n = FacetNormal(state.mesh) un = 0.5 * (dot(u0, n) + abs(dot(u0, n))) F = TrialFunction(Vu) w = TestFunction(Vu) self.uF = Function(Vu) outward_normals = CellNormal(state.mesh) perp = lambda u: cross(outward_normals, u) a = inner(w, F) * dx L = (-f * inner(w, perp(u0)) + g * div(w) * D0) * dx - g * inner( jump(w, n), un("+") * D0("+") - un("-") * D0("-") ) * dS if not linear: L -= 0.5 * div(w) * inner(u0, u0) * dx u_forcing_problem = LinearVariationalProblem(a, L, self.uF) self.u_forcing_solver = LinearVariationalSolver(u_forcing_problem)
def setup_solver(self, up_init=None): """ Setup the solvers """ self.up0 = Function(self.W) if up_init is not None: chk_in = checkpointing.HDF5File(up_init, file_mode='r') chk_in.read(self.up0, "/up") chk_in.close() self.u0, self.p0 = split(self.up0) self.up = Function(self.W) if up_init is not None: chk_in = checkpointing.HDF5File(up_init, file_mode='r') chk_in.read(self.up, "/up") chk_in.close() self.u1, self.p1 = split(self.up) self.up.sub(0).rename("velocity") self.up.sub(1).rename("pressure") v, q = TestFunctions(self.W) h = CellVolume(self.mesh) u_norm = sqrt(dot(self.u0, self.u0)) if self.has_nullspace: nullspace = MixedVectorSpaceBasis( self.W, [self.W.sub(0), VectorSpaceBasis(constant=True)]) else: nullspace = None tau = ((2.0 / self.dt)**2 + (2.0 * u_norm / h)**2 + (4.0 * self.nu / h**2)**2)**(-0.5) # temporal discretization F = (1.0 / self.dt) * inner(self.u1 - self.u0, v) * dx # weak form F += (+inner(dot(self.u0, nabla_grad(self.u1)), v) * dx + self.nu * inner(grad(self.u1), grad(v)) * dx - (1.0 / self.rho) * self.p1 * div(v) * dx + div(self.u1) * q * dx - inner(self.forcing, v) * dx) # residual form R = (+(1.0 / self.dt) * (self.u1 - self.u0) + dot(self.u0, nabla_grad(self.u1)) - self.nu * div(grad(self.u1)) + (1.0 / self.rho) * grad(self.p1) - self.forcing) # GLS F += tau * inner( +dot(self.u0, nabla_grad(v)) - self.nu * div(grad(v)) + (1.0 / self.rho) * grad(q), R) * dx self.problem = NonlinearVariationalProblem(F, self.up, self.bcs) self.solver = NonlinearVariationalSolver( self.problem, nullspace=nullspace, solver_parameters=self.solver_parameters)
def kinetic(self, u, factor=None): """ Computes 0.5*dot(u, u) with an option to multiply rho """ if factor is not None: energy = 0.5*factor*dot(u, u) else: energy = 0.5*dot(u, u) return energy
def linear_advection_form(state, test, qbar): ubar = Function(state.spaces("HDiv")) L = test * dot(ubar, state.k) * dot(state.k, grad(qbar)) * dx form = transporting_velocity(L, ubar) return transport(form, TransportEquationType.advective)
def advection_term(self, q): if self.continuity: n = FacetNormal(self.state.mesh) L = (-dot(grad(self.test), self.ubar) * self.qbar * dx + jump(self.ubar * self.test, n) * avg(self.qbar) * self.dS) else: L = self.test * dot(self.ubar, self.state.k) * dot( self.state.k, grad(self.qbar)) * dx return L
def topography_term(self): g = self.state.parameters.g u0, _ = split(self.x0) b = self.state.fields("topography") n = FacetNormal(self.state.mesh) un = 0.5 * (dot(u0, n) + abs(dot(u0, n))) L = g * div(self.test) * b * dx - g * inner( jump(self.test, n), un('+') * b('+') - un('-') * b('-')) * dS return L
def pressure_gradient_term(self): g = self.state.parameters.g u0, D0 = split(self.x0) n = FacetNormal(self.state.mesh) un = 0.5 * (dot(u0, n) + abs(dot(u0, n))) L = g * (div(self.test) * D0 * dx - inner(jump(self.test, n), un('+') * D0('+') - un('-') * D0('-')) * dS) return L
def dgls_form(self, problem, mesh, bcs_p): rho = problem.rho mu = problem.mu k = problem.k f = problem.f q, p = fire.TrialFunctions(self._W) w, v = fire.TestFunctions(self._W) n = fire.FacetNormal(mesh) h = fire.CellDiameter(mesh) # Stabilizing parameters has_mesh_characteristic_length = True delta_0 = fire.Constant(1) delta_1 = fire.Constant(-1 / 2) delta_2 = fire.Constant(1 / 2) delta_3 = fire.Constant(1 / 2) eta_p = fire.Constant(100) eta_q = fire.Constant(100) h_avg = (h("+") + h("-")) / 2.0 if has_mesh_characteristic_length: delta_2 = delta_2 * h * h delta_3 = delta_3 * h * h kappa = rho * k / mu inv_kappa = 1.0 / kappa # Classical mixed terms a = (dot(inv_kappa * q, w) - div(w) * p - delta_0 * v * div(q)) * dx L = -delta_0 * f * v * dx # DG terms a += jump(w, n) * avg(p) * dS - avg(v) * jump(q, n) * dS # Edge stabilizing terms a += (eta_q * h_avg) * avg(inv_kappa) * ( jump(q, n) * jump(w, n)) * dS + (eta_p / h_avg) * avg(kappa) * dot( jump(v, n), jump(p, n)) * dS # Add the contributions of the pressure boundary conditions to L for pboundary, iboundary in bcs_p: L -= pboundary * dot(w, n) * ds(iboundary) # Stabilizing terms a += (delta_1 * inner(kappa * (inv_kappa * q + grad(p)), delta_0 * inv_kappa * w + grad(v)) * dx) a += delta_2 * inv_kappa * div(q) * div(w) * dx a += delta_3 * inner(kappa * curl(inv_kappa * q), curl( inv_kappa * w)) * dx L += delta_2 * inv_kappa * f * div(w) * dx return a, L
def form_function(u, h, v, q): K = 0.5 * fd.inner(u, u) n = fd.FacetNormal(mesh) uup = 0.5 * (fd.dot(u, n) + abs(fd.dot(u, n))) Upwind = 0.5 * (fd.sign(fd.dot(u, n)) + 1) eqn = (fd.inner(v, f * perp(u)) * fd.dx - fd.inner(perp(fd.grad(fd.inner(v, perp(u)))), u) * fd.dx + fd.inner(both(perp(n) * fd.inner(v, perp(u))), both(Upwind * u)) * fd.dS - fd.div(v) * (g * (h + b) + K) * fd.dx - fd.inner(fd.grad(q), u) * h * fd.dx + fd.jump(q) * (uup('+') * h('+') - uup('-') * h('-')) * fd.dS) return eqn
def initialize_solvers(self): # Kinematics # Right Cauchy-Green tensor if self.nonlin: d = self.X.geometric_dimension() I = fd.Identity(d) # Identity tensor F = I + fd.grad(self.X) # Deformation gradient C = F.T * F E = (C - I) / 2. # Green-Lagrangian strain # E = 1./2.*( fd.grad(self.X).T + fd.grad(self.X) + fd.grad(self.X).T * fd.grad(self.X) ) # alternative equivalent definition else: E = 1. / 2. * (fd.grad(self.X).T + fd.grad(self.X) ) # linear strain self.W = (self.lam / 2.) * (fd.tr(E))**2 + self.mu * fd.tr(E * E) # f = fd.Constant((0, 0, -self.g)) # body force / rho # T = self.surface_force() # Total potential energy Pi = self.W * fd.dx # Compute first variation of Pi (directional derivative about X in the direction of v) F_expr = fd.derivative(Pi, self.X, self.v) self.DBC = fd.DirichletBC(self.V, fd.as_vector([0., 0., 0.]), self.bottom_id) # delX = fd.nabla_grad(self.X) # delv_B = fd.nabla_grad(self.v) # T_x_dv = self.lam * fd.div(self.X) * fd.div(self.v) \ # + self.mu * ( fd.inner( delX, delv_B + fd.transpose(delv_B) ) ) self.a_U = fd.dot(self.trial, self.v) * fd.dx # self.L_U = ( fd.dot( self.U, self.v ) - self.dt/2./self.rho * T_x_dv ) * fd.dx self.L_U = fd.dot( self.U, self.v) * fd.dx - self.dt / 2. / self.rho * F_expr #\ # + self.dt/2./self.rho*fd.dot(T,self.v)*fd.ds(1) # surface force at x==0 plane # + self.dt/2.*fd.dot(f,self.v)*fd.dx # body force self.a_X = fd.dot(self.trial, self.v) * fd.dx # self.L_interface = fd.dot(self.phi_vect, self.v) * fd.ds(self.interface_id) self.L_X = fd.dot((self.X + self.dt * self.U), self.v) * fd.dx #\ # - self.dt/self.rho * self.L_interface self.LVP_U = fd.LinearVariationalProblem(self.a_U, self.L_U, self.U, bcs=[self.DBC]) self.LVS_U = fd.LinearVariationalSolver(self.LVP_U) self.LVP_X = fd.LinearVariationalProblem(self.a_X, self.L_X, self.X, bcs=[self.DBC]) self.LVS_X = fd.LinearVariationalSolver(self.LVP_X)
def __init__(self, state, V, *, ibp="once", solver_params=None): self.state = state self.V = V self.ibp = ibp # set up functions required for forms self.ubar = Function(state.spaces("HDiv")) self.test = TestFunction(V) self.trial = TrialFunction(V) # find out if we are CG nvertex = V.ufl_domain().ufl_cell().num_vertices() entity_dofs = V.finat_element.entity_dofs() # If there are as many dofs on vertices as there are vertices, # assume a continuous space. try: self.is_cg = sum(map(len, entity_dofs[0].values())) == nvertex except KeyError: self.is_cg = sum(map(len, entity_dofs[(0, 0)].values())) == nvertex # DG, embedded DG and hybrid SUPG methods need surface measures, # n and un if self.is_cg: self.dS = None self.ds = None else: if V.extruded: self.dS = (dS_h + dS_v) self.ds = (ds_b + ds_t + ds_v) else: self.dS = dS self.ds = ds self.n = FacetNormal(state.mesh) self.un = 0.5 * (dot(self.ubar, self.n) + abs(dot(self.ubar, self.n))) if solver_params: self.solver_parameters = solver_params # default solver options else: self.solver_parameters = { 'ksp_type': 'cg', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu' } if state.output.log_level == DEBUG: self.solver_parameters["ksp_monitor_true_residual"] = True
def __init__(self, state, V, *, ibp="once", solver_params=None): super().__init__(state=state, V=V, ibp=ibp, solver_params=solver_params) self.Upwind = 0.5 * (sign(dot(self.ubar, self.n)) + 1) if self.state.mesh.topological_dimension() == 2: self.perp = state.perp if state.on_sphere: outward_normals = CellNormal(state.mesh) self.perp_u_upwind = lambda q: self.Upwind('+') * cross( outward_normals('+'), q('+')) + self.Upwind('-') * cross( outward_normals('-'), q('-')) else: self.perp_u_upwind = lambda q: self.Upwind('+') * state.perp( q('+')) + self.Upwind('-') * state.perp(q('-')) self.gradperp = lambda u: state.perp(grad(u)) elif self.state.mesh.topological_dimension() == 3: if self.ibp == "twice": raise NotImplementedError( "ibp=twice is not implemented for 3d problems") else: raise RuntimeError("topological mesh dimension must be 2 or 3")
def interpolate(self, mesh, k0L): V = fd.VectorFunctionSpace(mesh, "CG", 1) x = fd.SpatialCoordinate(mesh) pw = fd.interpolate(self.p * fd.exp(1j * k0L * fd.dot(self.s, x)), V) return pw
def add_dirichlet(self, g, surface): """ Adds dirichlet boundary conditions to the problem. Args: g (Function, int, or float): The function to apply on the boundary. surface (int or list of int): The index of the boundary to apply the condition to. """ # Explicitly check against False as None should not be caught here. if self._has_boundary is False: raise AttributeError('Cannot add boundary after declaring that ' 'there are no boundaries') norm = FacetNormal(self.mesh) if isinstance(g, (float, int)): g = Constant(g) integrand = -1 * self.v * dot(self.q, norm) if surface == 'all': dbc = DirichletBC(V=self.V, g=g, sub_domain="on_boundary") self.a += integrand * ds else: dbc = DirichletBC(V=self.V, g=g, sub_domain=surface) try: self.a += sum(integrand * ds(s) for s in surface) except TypeError: self.a += integrand * ds(surface) self.bcs.append(dbc) self._has_boundary = True
def test_ilu(): """Tests that ILU functionality gives correct solution.""" k = 10.0 num_cells = utils.h_to_num_cells(k**-1.5,2) mesh = fd.UnitSquareMesh(num_cells,num_cells) V = fd.FunctionSpace(mesh,"CG",1) prob = hh.HelmholtzProblem(k,V) angle = 2.0 * np.pi/7.0 d = [np.cos(angle),np.sin(angle)] prob.f_g_plane_wave(d) for fill_in in range(40): prob.use_ilu_gmres(fill_in) prob.solve() x = fd.SpatialCoordinate(mesh) # This error was found out by eye assert np.abs(fd.norms.errornorm(fd.exp(1j * k * fd.dot(fd.as_vector(d),x)),uh=prob.u_h,norm_type='H1')) < 0.5
def test_update_a_multiple_surfaces(self): """ Test a is updated correctly for a with a multiple surfaces. """ T = self.problem.T v = self.problem.v q = self.problem.q self.problem.a = T * dx g = Function(self.V) expected_a = T * dx + -1 * v * dot(q, self.norm) * ds(0) expected_a += -1 * v * dot(q, self.norm) * ds(1) self.problem.add_dirichlet(g, [0, 1]) self.assertEqual(expected_a, self.problem.a)
def poisson_gll(mesh, degree): V = FunctionSpace( mesh, FiniteElement('Q', mesh.ufl_cell(), degree, variant='spectral')) u = TrialFunction(V) v = TestFunction(V) dim = mesh.topological_dimension() finat_rule = gauss_lobatto_legendre_cube_rule(dim, degree) return dot(grad(u), grad(v)) * dx(rule=finat_rule)
def f_g_plane_wave(self, d): """Sets f and g to correspond to a plane wave Parameters - d - list of the length of the spatial dimension; the direction in which the plane wave propagates. """ d = fd.as_vector(d) self.set_f(0.0) x = fd.SpatialCoordinate(self.V.mesh()) nu = fd.FacetNormal(self.V.mesh()) self.set_g(1j*self._k*fd.exp(1j*self._k*fd.dot(x,d))\ *(fd.dot(d,nu)-1.0))
def A(fs): u = TrialFunction(fs) v = TestFunction(fs) a = (dot(grad(v), grad(u))) * dx bc = DirichletBC(fs, 0., "on_boundary") A = assemble(a, bcs = bc) return A
def _A(self): """ Create a stiffness matrix section. Returns: Function: A complete stiffness matrix section. """ return dot(self.q, grad(self.v)) * dx
def continuity_form(state, test, q, ibp=IntegrateByParts.ONCE, outflow=False): if outflow and ibp == IntegrateByParts.NEVER: raise ValueError( "outflow is True and ibp is None are incompatible options") Vu = state.spaces("HDiv") dS_ = (dS_v + dS_h) if Vu.extruded else dS ubar = Function(Vu) if ibp == IntegrateByParts.ONCE: L = -inner(grad(test), outer(q, ubar)) * dx else: L = inner(test, div(outer(q, ubar))) * dx if ibp != IntegrateByParts.NEVER: n = FacetNormal(state.mesh) un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n))) L += dot(jump(test), (un('+') * q('+') - un('-') * q('-'))) * dS_ if ibp == IntegrateByParts.TWICE: L -= (inner(test('+'), dot(ubar('+'), n('+')) * q('+')) + inner(test('-'), dot(ubar('-'), n('-')) * q('-'))) * dS_ if outflow: n = FacetNormal(state.mesh) un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n))) L += test * un * q * (ds_v + ds_t + ds_b) form = transporting_velocity(L, ubar) return ibp_label(transport(form, TransportEquationType.conservative), ibp)
def residual(self, test, trial, trial_lagged, fields, bcs): phi = test n = self.n p = fields['pressure'] # NOTE: we assume p is continuous F = dot(phi, grad(p))*self.dx # do nothing should be zero (normal) stress: F += -dot(phi, n)*p*self.ds # for those boundaries where the normal component of u is specified # we take it out again for id, bc in bcs.items(): if 'u' in bc or 'un' in bc: F += dot(phi, n)*p*self.ds(id) return -F
def vector_manifold_advection_form(state, test, q, ibp=IntegrateByParts.ONCE, outflow=False): L = advection_form(state, test, q, ibp, outflow) Vu = state.spaces("HDiv") dS_ = (dS_v + dS_h) if Vu.extruded else dS ubar = Function(Vu) n = FacetNormal(state.mesh) un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n))) L += un('+') * inner(test('-'), n('+') + n('-')) * inner(q('+'), n('+')) * dS_ L += un('-') * inner(test('+'), n('+') + n('-')) * inner(q('-'), n('-')) * dS_ return L
def curl_curl(mesh, degree): cell = mesh.ufl_cell() if cell.cellname() in ['interval * interval', 'quadrilateral']: hcurl_element = FiniteElement('RTCE', cell, degree) elif cell.cellname() == 'quadrilateral * interval': hcurl_element = FiniteElement('NCE', cell, degree) V = FunctionSpace(mesh, hcurl_element) u = TrialFunction(V) v = TestFunction(V) return dot(curl(u), curl(v)) * dx
def residual(self, test, trial, trial_lagged, fields, bcs): if 'source' not in fields: return 0 phi = test source = fields['source'] # NOTE, here source term F is already on the RHS F = dot(phi, source)*self.dx return F
def __init__(self, state, V, qbar, options=None): super(LinearAdvection_Vt, self).__init__(state) p = TestFunction(V) q = TrialFunction(V) self.dq = Function(V) a = p*q*dx k = state.k # Upward pointing unit vector L = -p*dot(self.ubar,k)*dot(k,grad(qbar))*dx aProblem = LinearVariationalProblem(a,L,self.dq) if options is None: options = {'ksp_type':'cg', 'pc_type':'bjacobi', 'sub_pc_type':'ilu'} self.solver = LinearVariationalSolver(aProblem, solver_parameters=options, options_prefix='LinearAdvectionVt')
def test_HelmholtzProblem_solver_convergence(): """Test that the solver is converging at the correct rate.""" k_range = [10.0,12.0,20.0,30.0,40.0]#[10.0,12.0]#[20.0,40.0] num_levels = 2 tolerance = 0.05 log_err_L2 = np.empty((num_levels,len(k_range))) log_err_H1 = np.empty((num_levels,len(k_range))) for ii_k in range(len(k_range)): k = k_range[ii_k] print(k) num_points = np.ceil(np.sqrt(2.0) * k**(1.5)) * 2.0**np.arange(float(num_levels)) log_h = np.log(np.sqrt(2.0) * 1.0 / num_points) for ii_points in range(num_levels): print(ii_points) # Coarsest grid has h ~ k^{-1.5}, and then do uniform refinement mesh = fd.UnitSquareMesh(num_points[ii_points],num_points[ii_points]) V = fd.FunctionSpace(mesh, "CG", 1) prob = hh.HelmholtzProblem(k,V) angle = 2.0*np.pi/7.0 d = [np.cos(angle),np.sin(angle)] prob.f_g_plane_wave(d) prob.solve() x = fd.SpatialCoordinate(mesh) exact_soln = fd.exp(1j * k * fd.dot(x,fd.as_vector(d))) log_err_L2[ii_points,ii_k] = np.log(fd.norms.errornorm(exact_soln,prob.u_h,norm_type="L2")) log_err_H1[ii_points,ii_k] = np.log(fd.norms.errornorm(exact_soln,prob.u_h,norm_type="H1")) #plt.plot(log_h,log_err_L2[:,ii_k]) #plt.plot(log_h,log_err_H1[:,ii_k]) #plt.show() fit_L2 = np.polyfit(log_h,log_err_L2[:,ii_k],deg=1)[0] fit_H1 = np.polyfit(log_h,log_err_H1[:,ii_k],deg=1)[0] print(fit_L2) print(fit_H1) assert abs(fit_L2 - 2.0) <= tolerance assert abs(fit_H1 - 1.0) <= tolerance
def vector_manifold_continuity_form(state, test, q, ibp=IntegrateByParts.ONCE, outflow=False): L = continuity_form(state, test, q, ibp, outflow) Vu = state.spaces("HDiv") dS_ = (dS_v + dS_h) if Vu.extruded else dS ubar = Function(Vu) n = FacetNormal(state.mesh) un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n))) L += un('+') * inner(test('-'), n('+') + n('-')) * inner(q('+'), n('+')) * dS_ L += un('-') * inner(test('+'), n('+') + n('-')) * inner(q('-'), n('-')) * dS_ form = transporting_velocity(L, ubar) return transport(form)
def setup(self, state): if not self._initialised: mesh_dim = state.mesh.geometric_dimension() try: field_dim = state.fields(self.fname).ufl_shape[0] except IndexError: field_dim = 1 shape = (mesh_dim, ) * field_dim space = TensorFunctionSpace(state.mesh, "CG", 1, shape=shape) super().setup(state, space=space) f = state.fields(self.fname) test = TestFunction(space) trial = TrialFunction(space) n = FacetNormal(state.mesh) a = inner(test, trial)*dx L = -inner(div(test), f)*dx if space.extruded: L += dot(dot(test, n), f)*(ds_t + ds_b) prob = LinearVariationalProblem(a, L, self.field) self.solver = LinearVariationalSolver(prob)
def estimate_timestep(mesh, V, c, estimate_max_eigenvalue=True): """Estimate the maximum stable timestep based on the spectral radius using optionally the Gershgorin Circle Theorem to estimate the maximum generalized eigenvalue. Otherwise computes the maximum generalized eigenvalue exactly ONLY WORKS WITH KMV ELEMENTS """ u, v = fd.TrialFunction(V), fd.TestFunction(V) quad_rule = finat.quadrature.make_quadrature( V.finat_element.cell, V.ufl_element().degree(), "KMV" ) dxlump = fd.dx(rule=quad_rule) A = fd.assemble(u * v * dxlump) ai, aj, av = A.petscmat.getValuesCSR() av_inv = [] for value in av: if value == 0: av_inv.append(0.0) else: av_inv.append(1 / value) Asp = scipy.sparse.csr_matrix((av, aj, ai)) Asp_inv = scipy.sparse.csr_matrix((av_inv, aj, ai)) K = fd.assemble(c*c*dot(grad(u), grad(v)) * dxlump) ai, aj, av = K.petscmat.getValuesCSR() Ksp = scipy.sparse.csr_matrix((av, aj, ai)) # operator Lsp = Asp_inv.multiply(Ksp) if estimate_max_eigenvalue: # absolute maximum of diagonals max_eigval = np.amax(np.abs(Lsp.diagonal())) else: print( "Computing exact eigenvalues is extremely computationally demanding!", flush=True, ) max_eigval = scipy.sparse.linalg.eigs( Ksp, M=Asp, k=1, which="LM", return_eigenvectors=False )[0] # print(max_eigval) if np.sqrt(max_eigval) > 0.0: max_dt = np.float(2 / np.sqrt(max_eigval)) else: max_dt = 100000000 #print( # f"Maximum stable timestep should be about: {np.float(2 / np.sqrt(max_eigval))} seconds", # flush=True, #) return max_dt
def __init__(self, state, V, continuity=False): super(DGAdvection, self).__init__(state) element = V.fiat_element assert element.entity_dofs() == element.entity_closure_dofs(), "Provided space is not discontinuous" dt = state.timestepping.dt if V.extruded: surface_measure = (dS_h + dS_v) else: surface_measure = dS phi = TestFunction(V) D = TrialFunction(V) self.D1 = Function(V) self.dD = Function(V) n = FacetNormal(state.mesh) # ( dot(v, n) + |dot(v, n)| )/2.0 un = 0.5*(dot(self.ubar, n) + abs(dot(self.ubar, n))) a_mass = inner(phi,D)*dx if continuity: a_int = -inner(grad(phi), outer(D, self.ubar))*dx else: a_int = -inner(div(outer(phi,self.ubar)),D)*dx a_flux = (dot(jump(phi), un('+')*D('+') - un('-')*D('-')))*surface_measure arhs = a_mass - dt*(a_int + a_flux) DGproblem = LinearVariationalProblem(a_mass, action(arhs,self.D1), self.dD) self.DGsolver = LinearVariationalSolver(DGproblem, solver_parameters={ 'ksp_type':'preonly', 'pc_type':'bjacobi', 'sub_pc_type': 'ilu'}, options_prefix='DGAdvection')
def __init__(self, state, V, qbar, options=None): super(LinearAdvection_V3, self).__init__(state) p = TestFunction(V) q = TrialFunction(V) self.dq = Function(V) n = FacetNormal(state.mesh) a = p*q*dx L = (dot(grad(p), self.ubar)*qbar*dx - jump(self.ubar*p, n)*avg(qbar)*(dS_v + dS_h)) aProblem = LinearVariationalProblem(a,L,self.dq) if options is None: options = {'ksp_type':'cg', 'pc_type':'bjacobi', 'sub_pc_type':'ilu'} self.solver = LinearVariationalSolver(aProblem, solver_parameters=options, options_prefix='LinearAdvectionV3')
def _setup_solver(self): state = self.state # just cutting down line length a bit dt = state.timestepping.dt beta = dt*state.timestepping.alpha cp = state.parameters.cp mu = state.mu # Split up the rhs vector (symbolically) u_in, rho_in, theta_in = split(state.xrhs) # Build the reduced function space for u,rho M = MixedFunctionSpace((state.V[0], state.V[1])) w, phi = TestFunctions(M) u, rho = TrialFunctions(M) n = FacetNormal(state.mesh) # Get background fields thetabar = state.thetabar rhobar = state.rhobar pibar = exner(thetabar, rhobar, state) pibar_rho = exner_rho(thetabar, rhobar, state) pibar_theta = exner_theta(thetabar, rhobar, state) # Analytical (approximate) elimination of theta k = state.k # Upward pointing unit vector theta = -dot(k,u)*dot(k,grad(thetabar))*beta + theta_in # Only include theta' (rather than pi') in the vertical # component of the gradient # the pi prime term (here, bars are for mean and no bars are # for linear perturbations) pi = pibar_theta*theta + pibar_rho*rho # vertical projection def V(u): return k*inner(u,k) eqn = ( inner(w, (u - u_in))*dx - beta*cp*div(theta*V(w))*pibar*dx # following does nothing but is preserved in the comments # to remind us why (because V(w) is purely vertical. # + beta*cp*jump(theta*V(w),n)*avg(pibar)*dS_v - beta*cp*div(thetabar*w)*pi*dx + beta*cp*jump(thetabar*w,n)*avg(pi)*dS_v + (phi*(rho - rho_in) - beta*inner(grad(phi), u)*rhobar)*dx + beta*jump(phi*u, n)*avg(rhobar)*(dS_v + dS_h) ) if mu is not None: eqn += dt*mu*inner(w,k)*inner(u,k)*dx aeqn = lhs(eqn) Leqn = rhs(eqn) # Place to put result of u rho solver self.urho = Function(M) # Boundary conditions (assumes extruded mesh) dim = M.sub(0).ufl_element().value_shape()[0] bc = ("0.0",)*dim bcs = [DirichletBC(M.sub(0), Expression(bc), "bottom"), DirichletBC(M.sub(0), Expression(bc), "top")] # Solver for u, rho urho_problem = LinearVariationalProblem( aeqn, Leqn, self.urho, bcs=bcs) self.urho_solver = LinearVariationalSolver(urho_problem, solver_parameters=self.params, options_prefix='ImplicitSolver') # Reconstruction of theta theta = TrialFunction(state.V[2]) gamma = TestFunction(state.V[2]) u, rho = self.urho.split() self.theta = Function(state.V[2]) theta_eqn = gamma*(theta - theta_in + dot(k,u)*dot(k,grad(thetabar))*beta)*dx theta_problem = LinearVariationalProblem(lhs(theta_eqn), rhs(theta_eqn), self.theta) self.theta_solver = LinearVariationalSolver(theta_problem, options_prefix='thetabacksubstitution')
def __init__(self, state, V): super(EulerPoincareForm, self).__init__(state) dt = state.timestepping.dt w = TestFunction(V) u = TrialFunction(V) self.u0 = Function(V) ustar = 0.5*(self.u0 + u) n = FacetNormal(state.mesh) Upwind = 0.5*(sign(dot(self.ubar, n))+1) if state.mesh.geometric_dimension() == 3: if V.extruded: surface_measure = (dS_h + dS_v) else: surface_measure = dS # <w,curl(u) cross ubar + grad( u.ubar)> # =<curl(u),ubar cross w> - <div(w), u.ubar> # =<u,curl(ubar cross w)> - # <<u_upwind, [[n cross(ubar cross w)cross]]>> both = lambda u: 2*avg(u) Eqn = ( inner(w, u-self.u0)*dx + dt*inner(ustar, curl(cross(self.ubar, w)))*dx - dt*inner(both(Upwind*ustar), both(cross(n, cross(self.ubar, w))))*surface_measure - dt*div(w)*inner(ustar, self.ubar)*dx ) # define surface measure and terms involving perp differently # for slice (i.e. if V.extruded is True) and shallow water # (V.extruded is False) else: if V.extruded: surface_measure = (dS_h + dS_v) perp = lambda u: as_vector([-u[1], u[0]]) perp_u_upwind = Upwind('+')*perp(ustar('+')) + Upwind('-')*perp(ustar('-')) else: surface_measure = dS outward_normals = CellNormal(state.mesh) perp = lambda u: cross(outward_normals, u) perp_u_upwind = Upwind('+')*cross(outward_normals('+'),ustar('+')) + Upwind('-')*cross(outward_normals('-'),ustar('-')) Eqn = ( (inner(w, u-self.u0) - dt*inner(w, div(perp(ustar))*perp(self.ubar)) - dt*div(w)*inner(ustar, self.ubar))*dx - dt*inner(jump(inner(w, perp(self.ubar)), n), perp_u_upwind)*surface_measure + dt*jump(inner(w, perp(self.ubar))*perp(ustar), n)*surface_measure ) a = lhs(Eqn) L = rhs(Eqn) self.u1 = Function(V) uproblem = LinearVariationalProblem(a, L, self.u1) self.usolver = LinearVariationalSolver(uproblem, options_prefix='EPAdvection')
def _setup_solver(self): state = self.state # just cutting down line length a bit dt = state.timestepping.dt beta = dt*state.timestepping.alpha mu = state.mu # Split up the rhs vector (symbolically) u_in, p_in, b_in = split(state.xrhs) # Build the reduced function space for u,p M = MixedFunctionSpace((state.V[0], state.V[1])) w, phi = TestFunctions(M) u, p = TrialFunctions(M) # Get background fields bbar = state.bbar # Analytical (approximate) elimination of theta k = state.k # Upward pointing unit vector b = -dot(k,u)*dot(k,grad(bbar))*beta + b_in # vertical projection def V(u): return k*inner(u,k) eqn = ( inner(w, (u - u_in))*dx - beta*div(w)*p*dx - beta*inner(w,k)*b*dx + phi*div(u)*dx ) if mu is not None: eqn += dt*mu*inner(w,k)*inner(u,k)*dx aeqn = lhs(eqn) Leqn = rhs(eqn) # Place to put result of u p solver self.up = Function(M) # Boundary conditions (assumes extruded mesh) dim = M.sub(0).ufl_element().value_shape()[0] bc = ("0.0",)*dim bcs = [DirichletBC(M.sub(0), Expression(bc), "bottom"), DirichletBC(M.sub(0), Expression(bc), "top")] # preconditioner equation L = self.L Ap = ( inner(w,u) + L*L*div(w)*div(u) + phi*p/L/L )*dx # Solver for u, p up_problem = LinearVariationalProblem( aeqn, Leqn, self.up, bcs=bcs, aP=Ap) nullspace = MixedVectorSpaceBasis(M, [M.sub(0), VectorSpaceBasis(constant=True)]) self.up_solver = LinearVariationalSolver(up_problem, solver_parameters=self.params, nullspace=nullspace) # Reconstruction of b b = TrialFunction(state.V[2]) gamma = TestFunction(state.V[2]) u, p = self.up.split() self.b = Function(state.V[2]) b_eqn = gamma*(b - b_in + dot(k,u)*dot(k,grad(bbar))*beta)*dx b_problem = LinearVariationalProblem(lhs(b_eqn), rhs(b_eqn), self.b) self.b_solver = LinearVariationalSolver(b_problem)
def __init__(self, state, V, direction=[], supg_params=None): super(SUPGAdvection, self).__init__(state) dt = state.timestepping.dt params = supg_params.copy() if supg_params else {} params.setdefault('a0', dt/sqrt(15.)) params.setdefault('a1', dt/sqrt(15.)) gamma = TestFunction(V) theta = TrialFunction(V) self.theta0 = Function(V) # make SUPG test function taus = [params["a0"], params["a1"]] for i in direction: taus[i] = 0.0 tau = Constant(((taus[0], 0.), (0., taus[1]))) dgamma = dot(dot(self.ubar, tau), grad(gamma)) gammaSU = gamma + dgamma n = FacetNormal(state.mesh) un = 0.5*(dot(self.ubar, n) + abs(dot(self.ubar, n))) a_mass = gammaSU*theta*dx arhs = a_mass - dt*gammaSU*dot(self.ubar, grad(theta))*dx if 1 in direction: arhs -= ( dt*dot(jump(gammaSU), (un('+')*theta('+') - un('-')*theta('-')))*dS_v - dt*(gammaSU('+')*dot(self.ubar('+'), n('+'))*theta('+') + gammaSU('-')*dot(self.ubar('-'), n('-'))*theta('-'))*dS_v ) if 2 in direction: arhs -= ( dt*dot(jump(gammaSU), (un('+')*theta('+') - un('-')*theta('-')))*dS_h - dt*(gammaSU('+')*dot(self.ubar('+'), n('+'))*theta('+') + gammaSU('-')*dot(self.ubar('-'), n('-'))*theta('-'))*dS_h ) self.theta1 = Function(V) self.dtheta = Function(V) problem = LinearVariationalProblem(a_mass, action(arhs,self.theta1), self.dtheta) self.solver = LinearVariationalSolver(problem, options_prefix='SUPGAdvection')
Ky.dat.data[...] = coords2ijk(coords[:, 0], coords[:, 1], coords[:, 2], Delta=Delta, data_array=ky_array) Kz.dat.data[...] = coords2ijk(coords[:, 0], coords[:, 1], coords[:, 2], Delta=Delta, data_array=kz_array) print("END: Read in reservoir fields") # Permeability field harmonic interpolation to facets Kx_facet = fd.conditional(fd.gt(fd.avg(Kx), 0.0), Kx('+')*Kx('-') / fd.avg(Kx), 0.0) Ky_facet = fd.conditional(fd.gt(fd.avg(Ky), 0.0), Ky('+')*Ky('-') / fd.avg(Ky), 0.0) Kz_facet = fd.conditional(fd.gt(fd.avg(Kz), 0.0), Kz('+')*Kz('-') / fd.avg(Kz), 0.0) # We can now define the bilinear and linear forms for the left and right dx = fd.dx KdivU = fd.as_vector((Kx_facet*u.dx(0), Ky_facet*u.dx(1), Kz_facet*u.dx(2))) a = (fd.dot(KdivU, fd.grad(v))) * dx m = u * v * phi * dx # Defining the eigenvalue problem petsc_a = fd.assemble(a).M.handle petsc_m = fd.assemble(m).M.handle num_eigenvalues = 3 # Set solver options opts = PETSc.Options() opts.setValue("eps_gen_hermitian", None) #opts.setValue("st_pc_factor_shift_type", "NONZERO") opts.setValue("eps_type", "krylovschur") #opts.setValue("eps_smallest_magnitude", None)
Khet = fd.as_tensor(((1.0 + x, 0, 0), (0, 1.0+y, 0), (0, 0, 1.0+z))) #Khet = fd.as_tensor(((1,0,0),(0,1,0),(0,0,1))) #Khet = fd.as_tensor(((1,0),(0,1))) Khet = fd.Function(W).interpolate(Khet) Khet.rename('K', 'Permeability') # Porosity por = fd.Constant(1.0) # We can now define the bilinear and linear forms for the left and right # hand sides of our equation respectively:: dx = fd.dx a = (fd.dot(Khet * fd.grad(u), fd.grad(v))) * dx m = u * v * por * dx # Defining the eigenvalue problem petsc_a = fd.assemble(a).M.handle petsc_m = fd.assemble(m).M.handle num_eigenvalues = 20 # Set solver options opts = PETSc.Options() opts.setValue("eps_gen_hermitian", None) #opts.setValue("st_pc_factor_shift_type", "NONZERO") opts.setValue("eps_type", "krylovschur") #opts.setValue("eps_smallest_magnitude", None)
def l2(f): return sqrt(assemble(dot(f, f)*dx))
def compute(self, state): u = state.field_dict['u'] dt = Constant(state.timestepping.dt) return self.field(state.mesh).project(sqrt(dot(u, u))/sqrt(self.area(state.mesh))*dt)