def weak_residual(self, x, x_test, m, e): """ The weak residual """ u, p, gamma = dl.split(x) u_test, p_test, g_test = dl.split(x_test) hbinv = hinv_u(self.metric, self.tg) res_u = dl.Constant(2.)*(self.nu+self.nu_t(x, m))*dl.inner( self.strain(u), self.strain(u_test))*dl.dx \ + dl.inner(dl.grad(u)*u, u_test)*dl.dx \ - p*dl.div(u_test)*dl.dx \ + self.Cd*(self.nu+self.nu_t(x, m))*hbinv*dl.dot(u - self.u_ff, self.tg)*dl.dot(u_test, self.tg)*self.ds_ff \ - dl.dot( self.sigma_n(self.nu+self.nu_t(x, m), u), self.tg) * dl.dot(u_test, self.tg)*self.ds_ff \ - dl.dot( self.sigma_n(self.nu+self.nu_t(x, m), u_test), self.tg ) * dl.dot(u - self.u_ff, self.tg)*self.ds_ff res_p = dl.div(u) * p_test * dl.dx D = self.nu_g(x, m, e) h_o_u = h_over_u(self.metric, u, D) res_g = dl.inner( D*dl.grad(gamma), dl.grad(g_test) )*dl.dx \ + h_o_u*dl.dot(u, dl.grad(gamma))*dl.dot(u, dl.grad(g_test))*dl.dx \ + dl.dot(u, dl.grad(gamma))*g_test*dl.dx \ - dl.Constant(.5)*gamma*g_test*(dl.dot(u, self.e1)/(self.xfun + self._offset(m)))*dl.dx return res_u + res_p + res_g
def computeVelocityField(mesh): Xh = dl.VectorFunctionSpace(mesh, 'Lagrange', 2) Wh = dl.FunctionSpace(mesh, 'Lagrange', 1) XW = dl.MixedFunctionSpace([Xh, Wh]) Re = 1e2 g = dl.Expression(('0.0', '(x[0] < 1e-14) - (x[0] > 1 - 1e-14)')) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v, q) = dl.split(vq) (v_test, q_test) = dl.TestFunctions(XW) def strain(v): return dl.sym(dl.nabla_grad(v)) F = ((2. / Re) * dl.inner(strain(v), strain(v_test)) + dl.inner(dl.nabla_grad(v) * v, v_test) - (q * dl.div(v_test)) + (dl.div(v) * q_test)) * dl.dx dl.solve(F == 0, vq, bcs, solver_parameters={ "newton_solver": { "relative_tolerance": 1e-4, "maximum_iterations": 100 } }) return v
def computeVelocityField(mesh): Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2) Wh = dl.FunctionSpace(mesh, 'Lagrange', 1) if dlversion() <= (1,6,0): XW = dl.MixedFunctionSpace([Xh, Wh]) else: mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(mesh, mixed_element) Re = 1e2 g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v,q) = dl.split(vq) (v_test, q_test) = dl.TestFunctions (XW) def strain(v): return dl.sym(dl.nabla_grad(v)) F = ( (2./Re)*dl.inner(strain(v),strain(v_test))+ dl.inner (dl.nabla_grad(v)*v, v_test) - (q * dl.div(v_test)) + ( dl.div(v) * q_test) ) * dl.dx dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver": {"relative_tolerance":1e-4, "maximum_iterations":100, "linear_solver":"default"}}) return v
def stokes(self): P2 = VectorElement("CG", self.mesh.ufl_cell(), 2) P1 = FiniteElement("CG", self.mesh.ufl_cell(), 1) TH = P2 * P1 VQ = FunctionSpace(self.mesh, TH) mf = self.mf self.no_slip = Constant((0., 0)) self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"), m=self.U_m, degree=2) bc0 = DirichletBC(VQ.sub(0), self.topflow, mf, self.bc_dict["top"]) bc1 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["left"]) bc2 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["bottom"]) bc3 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["right"]) # bc4 = DirichletBC(VQ.sub(1), Constant(0), mf, self.bc_dict["top"]) bcs = [bc0, bc1, bc2, bc3] vup = TestFunction(VQ) up = TrialFunction(VQ) # the solution will be in here: up_ = Function(VQ) u, p = split(up) # Trial vu, vp = split(vup) # Test u_, p_ = split(up_) # Function holding the solution F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \ - inner(vp, div(u))*dx + dot(self.g*self.rho, vu)*dx solve(lhs(F) == rhs(F), up_, bcs=bcs) self.u_.assign(project(u_, self.V)) self.p_.assign(project(p_, self.Q)) return
def __init__(self, parameters, domain): rho = Constant(parameters["density [kg/m3]"]) mu = Constant(parameters["viscosity [Pa*s]"]) dt = Constant(parameters["dt [s]"]) u, u_1, u_k, vu = domain.u, domain.u_1, domain.u_k, domain.vu p_1 = domain.p_1 n = FacetNormal(domain.mesh) acceleration = rho*inner((u-u_1)/dt, vu) * dx convection = dot(div(rho*outer(u_k, u)), vu) * dx convection = rho*dot(dot(u_k, nabla_grad(u)), vu) * dx pressure = (inner(p_1, div(vu))*dx - dot(p_1*n, vu)*ds) diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx) # good # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx # + dot(mu * (grad(u) + grad(u).T)*n, vu)*ds) # very slow! # F_impl = acceleration + convection + pressure + diffusion # dot(u_1, nabla_grad(u_1)) works # dot(u, nabla_grad(u_1)) does not change! u_mid = (u + u_1) / 2.0 F_impl = rho*dot((u - u_1) / dt, vu)*dx \ + rho*dot(dot(u_1, nabla_grad(u_1)), vu)*dx \ + inner(sigma(u_mid, p_1, mu), epsilon(vu))*dx \ + dot(p_1*n, vu)*ds - dot(mu*nabla_grad(u_mid)*n, vu)*ds self.a, self.L = lhs(F_impl), rhs(F_impl) self.domain = domain self.A = assemble(self.a) [bc.apply(self.A) for bc in domain.bcu] return
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, mu_f, rho_f, k, dt, v_deg, theta, **semimp_namespace): J_theta = theta * J_(d_["n"]) + (1 - theta) * J_(d_["n-1"]) F_fluid_linear = rho_f / k * inner(J_theta * (v_["n"] - v_["n-1"]), psi) * dx_f F_fluid_nonlinear = rho_f*inner((Constant(theta)*J_(d_["n"])*grad(v_["n"])*inv(F_(d_["n"])) + \ Constant(1 - theta)*J_(d_["n-1"])*grad(v_["n-1"])*inv(F_(d_["n-1"]))) * \ (0.5*(3*v_["n-1"] - v_["n-2"]) - \ 0.5/k*((3*d_["n-1"] - d_["n-2"]) - (3*d_["n-2"] - d_["n-3"]))), psi)*dx_f # F_fluid_nonlinear = rho_f*inner((Constant(theta)*J_(d_["n"])*grad(v_["n"])*inv(F_(d_["n"])) + \ # Constant(1 - theta)*J_(d_["n-1"])*grad(v_["n-1"])*inv(F_(d_["n-1"]))) * \ # (0.5*(3*v_["n-1"] - v_["n-2"]) -\ # (d_["n"]-d_["n-1"])/k), psi)*dx_f F_fluid_nonlinear += inner( J_(d_["n"]) * sigma_f_p(p_["n"], d_["n"]) * inv(F_(d_["n"])).T, grad(psi)) * dx_f F_fluid_nonlinear += Constant(theta) * inner( J_(d_["n"]) * sigma_f_u(v_["n"], d_["n"], mu_f) * inv(F_(d_["n"])).T, grad(psi)) * dx_f F_fluid_nonlinear += Constant(1 - theta) * inner( J_(d_["n-1"]) * sigma_f_u(v_["n-1"], d_["n-1"], mu_f) * inv(F_(d_["n-1"])).T, grad(psi)) * dx_f F_fluid_nonlinear += Constant(theta) * inner( div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]), gamma) * dx_f F_fluid_nonlinear += Constant(1 - theta) * inner( div(J_(d_["n-1"]) * inv(F_(d_["n-1"])) * v_["n-1"]), gamma) * dx_f #F_fluid_nonlinear +=inner(div(J_(d_["n"])*inv(F_(d_["n"]))*v_["n"]), gamma)*dx_f return dict(F_fluid_linear=F_fluid_linear, F_fluid_nonlinear=F_fluid_nonlinear)
def _generate_function_spaces(regularity, dim): """ Return a list of lambda functions, that, given a mesh and a degree, defines a conforming finite element spaces for the given space name """ if dim == 1: vFunctionSpace = FunctionSpace else: vFunctionSpace = VectorFunctionSpace spaces = {"h1": (lambda u, v: (dot(u,v) + inner(grad(u),grad(v)))*dx, [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg)]), "hdiv": (lambda u, v: (dot(u, v) + div(u)*div(v))*dx, [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg), lambda mesh, deg: FunctionSpace(mesh, "RT", deg), lambda mesh, deg: FunctionSpace(mesh, "BDM", deg)]), "hcurl": (lambda u, v: (dot(u, v) + inner(curl(u), curl(v)))*dx, [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg), lambda mesh, deg: FunctionSpace(mesh, "N1curl", deg)]), "l2": (lambda p, q: dot(p, q)*dx, [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg), lambda mesh, deg: vFunctionSpace(mesh, "DG", deg)]) } return spaces[regularity.lower()]
def main(): fsr = FunctionSubspaceRegistry() deg = 2 mesh = dolfin.UnitSquareMesh(100, 3) muc = mesh.ufl_cell() el_w = dolfin.FiniteElement('DG', muc, deg - 1) el_j = dolfin.FiniteElement('BDM', muc, deg) el_DG0 = dolfin.FiniteElement('DG', muc, 0) el = dolfin.MixedElement([el_w, el_j]) space = dolfin.FunctionSpace(mesh, el) DG0 = dolfin.FunctionSpace(mesh, el_DG0) fsr.register(space) facet_normal = dolfin.FacetNormal(mesh) xyz = dolfin.SpatialCoordinate(mesh) trial = dolfin.Function(space) test = dolfin.TestFunction(space) w, c = dolfin.split(trial) v, phi = dolfin.split(test) sympy_exprs = derive_exprs() exprs = { k: sympy_dolfin_printer.to_ufl(sympy_exprs['R'], mesh, v) for k, v in sympy_exprs['quantities'].items() } f = exprs['f'] w0 = dolfin.project(dolfin.conditional(dolfin.gt(xyz[0], 0.5), 1.0, 0.3), DG0) w_BC = exprs['w'] dx = dolfin.dx() form = (+v * dolfin.div(c) * dx - v * f * dx + dolfin.exp(w + w0) * dolfin.dot(phi, c) * dx + dolfin.div(phi) * w * dx - (w_BC - w0) * dolfin.dot(phi, facet_normal) * dolfin.ds() - (w0('-') - w0('+')) * dolfin.dot(phi('+'), facet_normal('+')) * dolfin.dS()) solver = NewtonSolver(form, trial, [], parameters=dict(relaxation_parameter=1.0, maximum_iterations=15, extra_iterations=10, relative_tolerance=1e-6, absolute_tolerance=1e-7)) solver.solve() with closing(XdmfPlot("out/qflop_test.xdmf", fsr)) as X: CG1 = dolfin.FunctionSpace(mesh, dolfin.FiniteElement('CG', muc, 1)) X.add('w0', 1, w0, CG1) X.add('w_c', 1, w + w0, CG1) X.add('w_e', 1, exprs['w'], CG1) X.add('f', 1, f, CG1) X.add('cx_c', 1, c[0], CG1) X.add('cx_e', 1, exprs['c'][0], CG1)
def setup_NS(w_NS, u, p, v, q, p0, q0, dx, ds, normal, dirichlet_bcs_NS, neumann_bcs, boundary_to_mark, u_1, rho_, rho_1, mu_, c_1, grad_g_c_, dt, grav, enable_EC, trial_functions, use_iterative_solvers, p_lagrange, mesh, q_rhs, density_per_concentration, K, **namespace): """ Set up the Navier-Stokes subproblem. """ mom_1 = rho_1 * u_1 if enable_EC and density_per_concentration is not None: for drhodci, ci_1, grad_g_ci_, Ki in zip( density_per_concentration, c_1, grad_g_c_, K): if drhodci > 0.: mom_1 += -drhodci*Ki*ci_1*grad_g_ci_ F = (1./dt * rho_1 * df.dot(u - u_1, v) * dx + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 2*mu_*df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx + 0.5*( 1./dt * (rho_ - rho_1) * df.inner(u, v) - df.inner(mom_1, df.nabla_grad(df.dot(u, v)))) * dx - p * df.div(v) * dx - q * df.div(u) * dx - rho_ * df.dot(grav, v) * dx) for boundary_name, pressure in neumann_bcs["p"].iteritems(): F += pressure * df.inner( normal, v) * ds(boundary_to_mark[boundary_name]) if enable_EC: F += sum([ci_1*df.dot(grad_g_ci_, v)*dx for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_)]) if p_lagrange: F += (p*q0 + q*p0)*dx if "u" in q_rhs: F += -df.dot(q_rhs["u"], v)*dx a, L = df.lhs(F), df.rhs(F) if not use_iterative_solvers: problem = df.LinearVariationalProblem(a, L, w_NS, dirichlet_bcs_NS) solver = df.LinearVariationalSolver(problem) else: solver = df.LUSolver("mumps") # solver.set_operator(A) return solver, a, L, dirichlet_bcs_NS return solver
def setup_NSu(w_NSu, u, v, dx, ds, normal, dirichlet_bcs_NSu, neumann_bcs, boundary_to_mark, u_, p_, u_1, p_1, rho_, rho_1, mu_, c_1, grad_g_c_, dt, grav, enable_EC, trial_functions, use_iterative_solvers, mesh, density_per_concentration, viscosity_per_concentration, K, **namespace): """ Set up the Navier-Stokes velocity subproblem. """ solvers = dict() mom_1 = rho_1 * u_1 if enable_EC and density_per_concentration is not None: for drhodci, ci_1, grad_g_ci_, Ki in zip(density_per_concentration, c_1, grad_g_c_, K): if drhodci > 0.: mom_1 += -drhodci * Ki * ci_1 * grad_g_ci_ F_predict = ( 1. / dt * rho_1 * df.dot(u - u_1, v) * dx + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 2 * mu_ * df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx + 0.5 * (1. / dt * (rho_ - rho_1) * df.dot(u, v) - df.inner(mom_1, df.grad(df.dot(u, v)))) * dx - p_1 * df.div(v) * dx - rho_ * df.dot(grav, v) * dx) for boundary_name, pressure in neumann_bcs["p"].iteritems(): F_predict += pressure * df.inner(normal, v) * ds( boundary_to_mark[boundary_name]) if enable_EC: F_predict += sum([ ci_1 * df.dot(grad_g_ci_, v) * dx for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_) ]) a_predict, L_predict = df.lhs(F_predict), df.rhs(F_predict) # if not use_iterative_solvers: problem_predict = df.LinearVariationalProblem(a_predict, L_predict, w_NSu, dirichlet_bcs_NSu) solvers["predict"] = df.LinearVariationalSolver(problem_predict) if use_iterative_solvers: solvers["predict"].parameters["linear_solver"] = "bicgstab" solvers["predict"].parameters["preconditioner"] = "amg" F_correct = (rho_ * df.inner(u - u_, v) * dx - dt * (p_ - p_1) * df.div(v) * dx) a_correct, L_correct = df.lhs(F_correct), df.rhs(F_correct) problem_correct = df.LinearVariationalProblem(a_correct, L_correct, w_NSu, dirichlet_bcs_NSu) solvers["correct"] = df.LinearVariationalSolver(problem_correct) if use_iterative_solvers: solvers["correct"].parameters["linear_solver"] = "bicgstab" solvers["correct"].parameters["preconditioner"] = "amg" #else: # solver = df.LUSolver("mumps") # # solver.set_operator(A) # return solver, a, L, dirichlet_bcs_NS return solvers
def _test_eigen_solver_sparse(callback_type): from rbnics.backends.dolfin import EigenSolver # Define mesh mesh = UnitSquareMesh(10, 10) # Define function space V_element = VectorElement("Lagrange", mesh.ufl_cell(), 2) Q_element = FiniteElement("Lagrange", mesh.ufl_cell(), 1) W_element = MixedElement(V_element, Q_element) W = FunctionSpace(mesh, W_element) # Create boundaries class Wall(SubDomain): def inside(self, x, on_boundary): return on_boundary and (x[1] < 0 + DOLFIN_EPS or x[1] > 1 - DOLFIN_EPS) boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0) wall = Wall() wall.mark(boundaries, 1) # Define variational problem vq = TestFunction(W) (v, q) = split(vq) up = TrialFunction(W) (u, p) = split(up) lhs = inner(grad(u), grad(v)) * dx - div(v) * p * dx - div(u) * q * dx rhs = -inner(p, q) * dx # Define boundary condition bc = [DirichletBC(W.sub(0), Constant((0., 0.)), boundaries, 1)] # Define eigensolver depending on callback type assert callback_type in ("form callbacks", "tensor callbacks") if callback_type == "form callbacks": solver = EigenSolver(W, lhs, rhs, bc) elif callback_type == "tensor callbacks": LHS = assemble(lhs) RHS = assemble(rhs) solver = EigenSolver(W, LHS, RHS, bc) # Solve the eigenproblem solver.set_parameters({ "linear_solver": "mumps", "problem_type": "gen_non_hermitian", "spectrum": "target real", "spectral_transform": "shift-and-invert", "spectral_shift": 1.e-5 }) solver.solve(1) r, c = solver.get_eigenvalue(0) assert abs(c) < 1.e-10 assert r > 0., "r = " + str(r) + " is not positive" print("Sparse inf-sup constant: ", sqrt(r)) return (sqrt(r), solver.condensed_A, solver.condensed_B)
def flux_derivative(self, u, coeff): """First derivative of flux.""" lmbda, mu = coeff Du = self.differential_op(u) I = Identity(u.cell().d) Dsigma = 2.0 * mu * div(Du) + dot(nabla_grad(lmbda), tr(Du) * I) if element_degree(u) >= 2: Dsigma += lmbda * div(tr(Du) * I) return Dsigma
def solve(self): """ Solve Stokes problem with current mesh """ (u, p) = TrialFunctions(self.VQ) (v, q) = TestFunctions(self.VQ) a = inner(grad(u), grad(v))*dx - div(u)*q*dx - div(v)*p*dx l = inner(self.f, v)*dx solve(a==l, self.w, bcs=self.bcs) self.u, self.p = self.w.split()
def strong_residual(self, x, m): """ The strong residual """ u, p = dl.split(x) res_u = -dl.div( dl.Constant(2.) * (self.nu + self.nu_t(m)) * self.strain(u)) + dl.grad(u) * u + dl.grad(p) res_p = dl.div(u) return [res_u, res_p]
def get_dwr_est(self, solns, adj_coarse, adj_fine): times_coarse = list(adj_coarse.keys()) times_coarse.sort() times_fine = list(adj_fine.keys()) times_fine.sort() ntimesteps = len(times_coarse) - 1 est = np.zeros(ntimesteps) u0 = solns[times_coarse[0]] div0 = self.heat_cond * dol.div(dol.grad(u0)) adv0 = self.direction * self.velo * dol.dot(dol.grad(u0), self.velocity) zc0 = adj_coarse[times_coarse[0]] f0 = dol.Function(self.V) self.f1.t = times_coarse[0] f0.interpolate(self.f1) f0 = f0 * self.src_weight zf0 = adj_fine[times_fine[0]] for t in range(ntimesteps): u1 = solns[times_coarse[t + 1]] div1 = self.heat_cond * dol.div(dol.grad(u1)) adv1 = self.direction * self.velo * dol.dot( dol.grad(u1), self.velocity) f1 = dol.Function(self.V) self.f1.t = times_coarse[t + 1] f1.interpolate(self.f1) f1 = f1 * self.src_weight zc1 = adj_coarse[times_coarse[t + 1]] zf1 = adj_fine[times_fine[2 * t + 1]] zf2 = adj_fine[times_fine[2 * t + 2]] dt = dol.Constant(times_coarse[t + 1] - times_coarse[t]) ut = (u1 - u0) / dt res_left = ut - div0 + adv0 - f0 res_right = ut - div1 + adv1 - f1 res_mid = (res_left + res_right) / 2 zz_left = zf0 - zc0 zz_right = zf2 - zc1 zz_mid = zf1 - (zc0 + zc1) / 2 part_left = dol.assemble(res_left * zz_left * dol.dx) part_right = dol.assemble(res_right * zz_right * dol.dx) part_mid = dol.assemble(res_mid * zz_mid * dol.dx) est[t] = abs(dt / 4 * (part_left + 2 * part_mid + part_right)) u0, div0, zc0, f0, zf0 = u1, div1, zc1, f1, zf2 return est
def fluid_setup(v_, p_, n, psi, gamma, dx, mu_f, rho_f, k, dt, theta, **semimp_namespace): F_fluid_linear = rho_f/k*inner(v_["n"] - v_["n-1"], psi)*dx \ + Constant(theta)*inner(sigma_f(p_["n"], v_["n"], mu_f), grad(psi))*dx \ + Constant(1 - theta)*inner(sigma_f(p_["n-1"], v_["n-1"], mu_f), grad(psi))*dx \ + Constant(theta)*inner(div(v_["n"]), gamma)*dx \ + Constant(1 -theta)*inner(div(v_["n-1"]), gamma)*dx F_fluid_nonlinear = Constant(theta)*rho_f*inner(dot(grad(v_["n"]), v_["n"]), psi)*dx \ + Constant(1 - theta)*rho_f*inner(dot(grad(v_["n-1"]), v_["n-1"]), psi)*dx return dict(F_fluid_linear=F_fluid_linear, F_fluid_nonlinear=F_fluid_nonlinear)
def test_is_zero_with_nabla(): mesh = UnitSquareMesh(4, 4) V1 = FunctionSpace(mesh, 'CG', 1) V2 = VectorFunctionSpace(mesh, 'CG', 1) v1 = TestFunction(V1) v2 = TrialFunction(V2) n = Constant([1, 1]) nn = dolfin.outer(n, n) vv = dolfin.outer(v2, v2) check_is_zero(dot(n, grad(v1)), 1) check_is_zero(dolfin.div(v2), 1) check_is_zero(dot(dolfin.div(nn), n), 0) check_is_zero(dot(dolfin.div(vv), n), 1) check_is_zero(dolfin.inner(nn, grad(v2)), 1)
def integrateFluidStress(v, p, nu, space_dim): if space_dim == 2: cd_integral = -20. * (nu * v_ref * (1. / l_ref**2) * inner( dlfn.nabla_grad(v), dlfn.nabla_grad(vd)) + v_ref**2 * (1. / l_ref) * inner(grad(v) * v, vd) - p_ref * (1. / l_ref) * p * dlfn.div(vd)) * dV cd = l_ref**2 * dlfn.assemble(cd_integral) cl_integral = -20. * (nu * v_ref * (1. / l_ref**2) * inner( dlfn.nabla_grad(v), dlfn.nabla_grad(vl)) + v_ref**2 * (1. / l_ref) * inner(grad(v) * v, vl) - p_ref * (1. / l_ref) * p * dlfn.div(vl)) * dV cl = l_ref**2 * dlfn.assemble(cl_integral) else: raise ValueError("space dimension unequal 2") return cd, cl
def delta_dg(mesh, expr): CG = df.FunctionSpace(mesh, "CG", 1) DG = df.FunctionSpace(mesh, "DG", 0) CG3 = df.VectorFunctionSpace(mesh, "CG", 1) DG3 = df.VectorFunctionSpace(mesh, "DG", 0) m = df.interpolate(expr, DG3) n = df.FacetNormal(mesh) u_dg = df.TrialFunction(DG) v_dg = df.TestFunction(DG) u3 = df.TrialFunction(CG3) v3 = df.TestFunction(CG3) a = u_dg * df.inner(v3, n) * df.ds - u_dg * df.div(v3) * df.dx mm = m.vector().array() mm.shape = (3, -1) K = df.assemble(a).array() L3 = df.assemble(df.dot(v3, df.Constant([1, 1, 1])) * df.dx).array() f = np.dot(K, mm[0]) / L3 fun1 = df.Function(CG3) fun1.vector().set_local(f) df.plot(fun1) a = df.div(u3) * v_dg * df.dx A = df.assemble(a).array() L = df.assemble(v_dg * df.dx).array() h = np.dot(A, f) / L fun = df.Function(DG) fun.vector().set_local(h) df.plot(fun) res = [] for x in xs: res.append(fun(x, 5, 0.5)) """ fun2 =df.interpolate(fun, df.VectorFunctionSpace(mesh, "CG", 1)) file = df.File('field2.pvd') file << fun2 """ return res
def compute_velocity(mesh, Vh, a, u): #export the velocity field v = - exp( a ) \grad u: then we solve ( exp(-a) v, w) = ( u, div w) Vv = dl.FunctionSpace(mesh, 'RT', 1) v = dl.Function(Vv, name="velocity") vtrial = dl.TrialFunction(Vv) vtest = dl.TestFunction(Vv) afun = dl.Function(Vh[PARAMETER], a) ufun = dl.Function(Vh[STATE], u) Mv = dl.exp(-afun) * dl.inner(vtrial, vtest) * dl.dx n = dl.FacetNormal(mesh) class TopBoundary(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1 - dl.DOLFIN_EPS Gamma_M = TopBoundary() boundaries = dl.FacetFunction("size_t", mesh) boundaries.set_all(0) Gamma_M.mark(boundaries, 1) dss = dl.Measure("ds")[boundaries] rhs = ufun * dl.div(vtest) * dl.dx - dl.dot(vtest, n) * dss(1) bcv = dl.DirichletBC(Vv, dl.Expression(("0.0", "0.0")), v_boundary) dl.solve(Mv == rhs, v, bcv) return v
def Coupled_setup(d_, v_, p_, psi_v, psi_p, psi_d, dS2, n, mu_f, body_force, dx_s, dx_f, mu_s, rho_s, lamda_s, k, mesh_file, rho_f, **semimp_namespace): F_coupled_linear = rho_s / k**2 * inner( d_["n"] - 2 * d_["n-1"] + d_["n-2"], psi_d) * dx_s F_coupled_linear -= rho_s * inner(body_force, psi_d) * dx_s F_coupled_linear = rho_f / k * J_(d_["tilde"]) * inner( v_["n"] - v_["tilde"], psi_v) * dx_f F_coupled_linear += J_(d_["tilde"]) * inner( inv(F_(d_["tilde"])).T * grad(p_["n"]), psi_v) * dx_f F_coupled_linear += inner( div(J_(d_["tilde"]) * inv(F_(d_["tilde"])) * v_["n"]), psi_p) * dx_f # Non-linear part F_coupled_nonlinear = Constant(0.5) * inner(Piola1(d_["n"], lamda_s, mu_s), grad(psi_d))*dx_s \ + Constant(0.5) * inner(Piola1(d_["n-2"], lamda_s, mu_s), grad(psi_d))*dx_s # Impose BC weakly F_coupled_nonlinear -= inner(J_(d_["tilde"]("+"))*sigma_f(p_["n"]("+"), v_["tilde"]("+"), d_["tilde"]("+"), mu_f) \ * inv(F_(d_["tilde"]("+"))).T*n("+"), psi_d("+"))*dS2(5) # TODO: This might be better strongly... F_coupled_linear += J_(d_["tilde"]("+")) * inner( dot(v_["n"]("+") - -(d_["n"]("-") - d_["n-1"]("-")) / k, n("+")), psi_p("+")) * dS2(5) return dict(F_coupled_linear=F_coupled_linear, F_coupled_nonlinear=F_coupled_nonlinear)
def __init__(self, domain): rho, mu, dt, g = domain.rho, domain.mu, domain.dt, domain.g u, u_1, vu = domain.u, domain.u_1, domain.vu p_1 = domain.p_1 n = FacetNormal(domain.mesh) acceleration = rho * inner((u - u_1) / dt, vu) * dx pressure = inner(p_1, div(vu)) * dx - dot(p_1 * n, vu) * ds body_force = dot(g*rho, vu)*dx \ + dot(Constant((0.0, 0.0)), vu) * ds # diffusion = (-inner(mu * (grad(u_1) + grad(u_1).T), grad(vu))*dx # + dot(mu * (grad(u_1) + grad(u_1).T)*n, vu)*ds) # just fine # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx) # just fine # just fine, but horribly slow in combination with ??? -> not reproducable diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu)) * dx + dot(mu * (grad(u) + grad(u).T) * n, vu) * ds) # convection = rho*dot(dot(u, nabla_grad(u_1)), vu) * dx # no vortices convection = rho * dot(dot(u_1, nabla_grad(u)), vu) * dx # stabilization = -gamma*psi_p*p_1 # convection = dot(div(rho * outer(u_1, u_1)), vu) * dx # not stable! # convection = rho * dot(dot(u_1, nabla_grad(u_1)), vu) * dx # just fine F_impl = -acceleration - convection + diffusion + pressure + body_force self.a, self.L = lhs(F_impl), rhs(F_impl) self.domain = domain self.A = assemble(self.a) [bc.apply(self.A) for bc in domain.bcu] return
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, dS, mu_f, rho_f, k, v_deg, **semimp_namespace): F_fluid_linear = (rho_f / k) * inner( J_(d_["n"]) * (v_["n"] - v_["n-1"]), psi) * dx_f F_fluid_linear -= inner(div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]), gamma) * dx_f F_fluid_linear += inner( J_(d_["n"]) * sigma_f_new(v_["n"], p_["n"], d_["n"], mu_f) * inv(F_(d_["n"])).T, grad(psi)) * dx_f F_fluid_linear -= inner(dot(J_(d_["n"]("-"))*\ sigma_f_new(v_["n"]("-"), p_["n"]("-"), d_["n"]("-"), mu_f)*inv(F_(d_["n"]("-"))).T, n("+")) , psi("-") )*dS(5) F_fluid_nonlinear = rho_f * inner( J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) * (v_["n"] - ((d_["n"] - d_["n-1"]) / k)), psi) * dx_f if v_deg == 1: F_fluid -= beta * h * h * inner( J_(d_["n"]) * inv(F_(d_["n"]).T) * grad(p), grad(gamma)) * dx_f print "v_deg", v_deg return dict(F_fluid_linear=F_fluid_linear, F_fluid_nonlinear=F_fluid_nonlinear)
def __init__(self, V, expression_type, basis_generation): self.V = V # Parametrized function to be interpolated mock_problem = MockProblem(V) f1 = ParametrizedExpression( mock_problem, "1/sqrt(pow(x[0]-mu[0], 2) + pow(x[1]-mu[1], 2) + 0.01)", mu=(-1., -1.), element=V.sub(1).ufl_element()) # folder_prefix = os.path.join("test_eim_approximation_08_tempdir", expression_type, basis_generation) assert expression_type in ("Vector", "Matrix") if expression_type == "Vector": q = TestFunction(V.sub(1).collapse()) form = f1 * q * dx # Call Parent constructor EIMApproximation.__init__(self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) elif expression_type == "Matrix": up = TrialFunction(V) q = TestFunction(V.sub(1).collapse()) (u, p) = split(up) form = f1 * q * div(u) * dx # Call Parent constructor EIMApproximation.__init__(self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) else: # impossible to arrive here anyway thanks to the assert raise AssertionError("Invalid expression_type")
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx()) C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) return C
def tail(self, t, it, logger): cc = self.cc pv = self.pv # Get div(v) locally div_v = self.div_v if div_v is not None: div_v.assign( df.project(df.div(pv["v"]), div_v.function_space())) # Compute required functionals keys = ["t", "E_kin", "Psi", "mean_p"] vals = {} vals[keys[0]] = t vals[keys[1]] = df.assemble(0.5 * cc["rho"] * df.inner(pv["v"], pv["v"]) * df.dx) vals[keys[2]] = df.assemble(( 0.25 * cc["a"] * cc["eps"] *\ df.inner(df.dot(cc["LA"], df.grad(pv["phi"])), df.grad(pv["phi"])) + (cc["b"] / cc["eps"]) * cc["F"] ) * df.dx) vals[keys[3]] = df.assemble(pv["p"] * df.dx) if it % self.mod == 0: for key in keys: self.functionals[key].append(vals[key]) # Logging and reporting df.info("") df.begin("Reported functionals:") for key in keys[1:]: desc = "{:6s} = %g".format(key) logger.info(desc, (vals[key], ), (key, ), t) df.end() df.info("")
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG)) * dx()) C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) return C
def incompressibilityCondition(self, v): """ Return the incompressibility function, :math:`f(\mathbf{v})`, for fluids such that :math:`f(\mathbf{v}) = 0`. The default is .. math:: f(\mathbf{v}) = \\text{div}(\mathbf{v}) = 0, where :math:`\mathbf{v}` is the velocity vector field. This can be redefined by subclasses if a different constraint function is desired. Parameters ---------- v : dolfin.Function, ufl.tensors.ListTensor The velocity vector. Returns ------- f : ufl.differentiation.Div UFL object defining the incompressibility condition. """ return dlf.div(v)
def create_forms(W, rho, nu, g_a, boundary_markers, gamma=0.0): v, p = df.TrialFunctions(W) v_t, p_t = df.TestFunctions(W) a = ( 2.0 * nu * df.inner(df.sym(df.grad(v)), df.grad(v_t)) - p * df.div(v_t) - df.div(v) * p_t #- nu * df.div(v) * p_t ) * df.dx L = rho * df.inner(df.Constant((0.0, -g_a)), v_t) * df.dx # Grad-div stabilization a += df.Constant(gamma) * df.div(v) * df.div(v_t) * df.dx return a, L
def __init__(self, V, expression_type, basis_generation): self.V = V # Parametrized function to be interpolated mock_problem = MockProblem(V) f1 = ParametrizedExpression( mock_problem, "1/sqrt(pow(x[0]-mu[0], 2) + pow(x[1]-mu[1], 2) + 0.01)", mu=(-1., -1.), element=V.sub(1).ufl_element()) f2 = ParametrizedExpression( mock_problem, "exp( - 2*pow(x[0]-mu[0], 2) - 2*pow(x[1]-mu[1], 2) )", mu=(-1., -1.), element=V.sub(1).ufl_element()) f3 = ParametrizedExpression( mock_problem, "(1-x[0])*cos(3*pi*(pi+mu[1])*(1+x[1]))*exp(-(pi+mu[0])*(1+x[0]))", mu=(-1., -1.), element=V.sub(1).ufl_element()) # folder_prefix = os.path.join("test_eim_approximation_05_tempdir", expression_type, basis_generation) assert expression_type in ("Vector", "Matrix") if expression_type == "Vector": vq = TestFunction(V) (v, q) = split(vq) form = f1 * v[0] * dx + f2 * v[1] * dx + f3 * q * dx # Call Parent constructor EIMApproximation.__init__( self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) elif expression_type == "Matrix": up = TrialFunction(V) vq = TestFunction(V) (u, p) = split(up) (v, q) = split(vq) form = f1 * inner(grad(u), grad(v)) * dx + f2 * p * div(v) * dx + f3 * q * div(u) * dx # Call Parent constructor EIMApproximation.__init__( self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) else: # impossible to arrive here anyway thanks to the assert raise AssertionError("Invalid expression_type")
def get_residual_form(u, v, rho_e, E = 1, method='SIMP'): if method =='SIMP': C = rho_e**3 else: C = rho_e/(1 + 8. * (1. - rho_e)) E = 1. * C # C is the design variable, its values is from 0 to 1 nu = 0.3 # Poisson's ratio lambda_ = E * nu/(1. + nu)/(1 - 2 * nu) mu = E / 2 / (1 + nu) #lame's parameters w_ij = 0.5 * (df.grad(u) + df.grad(u).T) v_ij = 0.5 * (df.grad(v) + df.grad(v).T) d = len(u) sigm = lambda_*df.div(u)*df.Identity(d) + 2*mu*w_ij a = df.inner(sigm, v_ij) * df.dx return a
def flux_derivative(self, u, coeff): a = coeff Du = self.differential_op(u) Dsigma = dot(nabla_grad(a), Du) if element_degree(u) >= 2: Dsigma += a * div(Du) return Dsigma
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, mu_f, rho_f, k, dt, v_deg, theta, **semimp_namespace): #J_theta = theta*J_(d_["n"]) + (1 - theta)*J_(d_["n-1"]) #F_fluid_linear = rho_f/k*inner(J_theta*(v_["n"] - v_["n-1"]), psi)*dx_f #F_fluid_nonlinear = rho_f/k*inner(J_theta*(v_["n"] - v_["n-1"]), psi)*dx_f J_theta = theta * J_(d_["n"]) + (1 - theta) * J_(d_["n-1"]) F_fluid_nonlinear = rho_f / k * inner( J_theta * (v_["n"]) - theta * J_(d_["n"]) * v_["n-1"], psi) * dx_f F_fluid_linear = rho_f / k * inner( Constant(1 - theta) * J_(d_["n-1"]) * -(v_["n-1"]), psi) * dx_f F_fluid_nonlinear = Constant(theta) * rho_f * inner( J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) * v_["n"], psi) * dx_f F_fluid_nonlinear += inner( J_(d_["n"]) * sigma_f_p(p_["n"], d_["n"]) * inv(F_(d_["n"])).T, grad(psi)) * dx_f F_fluid_nonlinear += Constant(theta) * inner( J_(d_["n"]) * sigma_f_u(v_["n"], d_["n"], mu_f) * inv(F_(d_["n"])).T, grad(psi)) * dx_f F_fluid_linear += Constant(1 - theta) * inner( J_(d_["n-1"]) * sigma_f_u(v_["n-1"], d_["n-1"], mu_f) * inv(F_(d_["n-1"])).T, grad(psi)) * dx_f F_fluid_nonlinear += inner(div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]), gamma) * dx_f F_fluid_linear += Constant(1 - theta) * rho_f * inner( J_(d_["n-1"]) * grad(v_["n-1"]) * inv(F_(d_["n-1"])) * v_["n-1"], psi) * dx_f F_fluid_nonlinear -= rho_f * inner( J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) * ((d_["n"] - d_["n-1"]) / k), psi) * dx_f return dict(F_fluid_linear=F_fluid_linear, F_fluid_nonlinear=F_fluid_nonlinear)
def get_residual_form(u, v, rho_e, T, T_hat, KAPPA, k, alpha, mode='plane_stress', method='RAMP', T_r=df.Constant(20.)): if method=='RAMP': p =8 C = rho_e/(1 + p * (1. - rho_e)) else: C = rho_e**3 E = k * C # C is the design variable, its values is from 0 to 1 nu = 0.3 # Poisson's ratio lambda_ = E * nu/(1. + nu)/(1 - 2 * nu) mu = E / 2 / (1 + nu) #lame's parameters if mode == 'plane_stress': lambda_ = 2*mu*lambda_/(lambda_+2*mu) # Th = df.Constant(7) I = df.Identity(len(u)) T_0 = df.Constant(20.) w_ij = 0.5 * (df.grad(u) + df.grad(u).T) - C * alpha * I * (T-T_0) v_ij = 0.5 * (df.grad(v) + df.grad(v).T) d = len(u) sigm = lambda_*df.div(u)*df.Identity(d) + 2*mu*w_ij a = df.inner(sigm, v_ij) * df.dx + \ df.dot(C*KAPPA* df.grad(T), df.grad(T_hat)) * df.dx print("get a-------") return a
def __init__(self, u_, Space, bcs=[], name="div", method={}): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) Source = u_[0].function_space() if not low_memory_version: self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]] for i in range(Space.mesh().geometry().dim())] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) self.WGM = [] st = TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): dP = assemble(st.dx(i) * TestFunction(DG) * dx) A = Matrix(G) self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg))
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx()) compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) M_mat = as_backend_type(M).mat() M_mat.matMult(A.mat()) return M
def comp_cont_error(v, fpbc, Q): """Compute the L2 norm of the residual of the continuity equation Bv = g """ q = TrialFunction(Q) divv = assemble(q*div(v)*dx) conRhs = Function(Q) conRhs.vector().set_local(fpbc) ContEr = norm(conRhs.vector() - divv) return ContEr
def _residual_strong(dx, v, phi, mu, sigma, omega, conv, voltages): '''Get the residual in strong form, projected onto V. ''' r = Expression('x[0]', degree=1, cell=triangle) R = [zero() * dx(0), zero() * dx(0)] subdomain_indices = mu.keys() for i in subdomain_indices: # diffusion, reaction R_r = - div(1 / (mu[i] * r) * grad(r * phi[0])) \ - sigma[i] * omega * phi[1] R_i = - div(1 / (mu[i] * r) * grad(r * phi[1])) \ + sigma[i] * omega * phi[0] # convection if i in conv: R_r += dot(conv[i], 1 / r * grad(r * phi[0])) R_i += dot(conv[i], 1 / r * grad(r * phi[1])) # right-hand side if i in voltages: R_r -= sigma[i] * voltages[i].real / (2 * pi * r) R_i -= sigma[i] * voltages[i].imag / (2 * pi * r) R[0] += R_r * v * dx(i) R[1] += R_i * v * dx(i) return R
def adaptive(self, mesh, eigv, eigf): """Refine mesh based on residual errors.""" fraction = 0.1 C = FunctionSpace(mesh, "DG", 0) # constants on triangles w = TestFunction(C) h = CellSize(mesh) n = FacetNormal(mesh) marker = CellFunction("bool", mesh) print len(marker) indicators = np.zeros(len(marker)) for e, u in zip(eigv, eigf): errform = avg(h) * jump(grad(u), n) ** 2 * avg(w) * dS \ + h * (inner(grad(u), n) - Constant(e) * u) ** 2 * w * ds if self.degree > 1: errform += h ** 2 * div(grad(u)) ** 2 * w * dx indicators[:] += assemble(errform).array() # errors for each cell print "Residual error: ", sqrt(sum(indicators) / len(eigv)) cutoff = sorted( indicators, reverse=True)[ int(len(indicators) * fraction) - 1] marker.array()[:] = indicators > cutoff # mark worst errors mesh = refine(mesh, marker) return mesh
def ab2tr_step(W, P, dt0, dt_1, mu, rho, u0, u_1, u_bcs, dudt0, dudt_1, dudt_bcs, p_1, p_bcs, f0, f1, tol=1.0e-12, verbose=True ): # General AB2/TR step. # # Steps are labeled in the following way: # # * u_1: previous step. # * u0: current step. # * u1: next step. # # The same scheme applies to all other entities. # WP = W * P # Make sure the boundary conditions fit with the space. u_bcs_new = [] for u_bc in u_bcs: u_bcs_new.append(DirichletBC(WP.sub(0), u_bc.value(), u_bc.user_sub_domain())) p_bcs_new = [] for p_bc in p_bcs: p_bcs_new.append(DirichletBC(WP.sub(1), p_bc.value(), p_bc.user_sub_domain())) # Predict velocity. if dudt_1: u_pred = u0 \ + 0.5*dt0*((2 + dt0/dt_1) * dudt0 - (dt0/dt_1) * dudt_1) else: # Simple linear extrapolation. u_pred = u0 + dt0 * dudt0 uu = TrialFunctions(WP) vv = TestFunctions(WP) # Assign up[1] with u_pred and up[1] with p_1. # As of now (2013/09/05), there is no proper subfunction assignment in # Dolfin, cf. # <https://bitbucket.org/fenics-project/dolfin/issue/84/subfunction-assignment>. # Hence, we need to be creative here. # TODO proper subfunction assignment # # up1.assign(0, u_pred) # up1.assign(1, p_1) # up1 = Function(WP) a = (dot(uu[0], vv[0]) + uu[1] * vv[1]) * dx L = dot(u_pred, vv[0]) * dx if p_1: L += p_1 * vv[1] * dx solve(a == L, up1, bcs=u_bcs_new + p_bcs_new ) # Split up1 for easier access. # This is not as easy as it may seem at first, see # <http://fenicsproject.org/qa/1123/nonlinear-solves-with-mixed-function-spaces>. # Note in particular that # u1, p1 = up1.split() # doesn't work here. # u1, p1 = split(up1) # Form the nonlinear equation system (3.16-235) in Gresho/Sani. # Left-hand side of the nonlinear equation system. F = 2.0/dt0 * rho * dot(u1, vv[0]) * dx \ + mu * inner(grad(u1), grad(vv[0])) * dx \ + rho * 0.5 * (inner(grad(u1)*u1, vv[0]) - inner(grad(vv[0]) * u1, u1)) * dx \ + dot(grad(p1), vv[0]) * dx \ + div(u1) * vv[1] * dx # Subtract the right-hand side. F -= dot(rho*(2.0/dt0*u0 + dudt0) + f1, vv[0]) * dx #J = derivative(F, up1) # Solve nonlinear system for u1, p1. solve( F == 0, up1, bcs=u_bcs_new + p_bcs_new, #J = J, solver_parameters={ #'nonlinear_solver': 'snes', 'nonlinear_solver': 'newton', 'newton_solver': {'maximum_iterations': 5, 'report': True, 'absolute_tolerance': tol, 'relative_tolerance': 0.0 }, 'linear_solver': 'direct', #'linear_solver': 'iterative', ## The nonlinear term makes the problem ## generally nonsymmetric. #'symmetric': False, ## If the nonsymmetry is too strong, e.g., if ## u_1 is large, then AMG preconditioning ## might not work very well. #'preconditioner': 'ilu', ##'preconditioner': 'hypre_amg', #'krylov_solver': {'relative_tolerance': tol, # 'absolute_tolerance': 0.0, # 'maximum_iterations': 100, # 'monitor_convergence': verbose} }) ## Simpler access to the solution. #u1, p1 = up1.split() # Invert trapezoidal rule for next du/dt. dudt1 = 2 * (u1 - u0)/dt0 - dudt0 # Get next dt. if dt_1: # Compute local trunction error (LTE) estimate. d = (u1 - u_pred) / (3*(1.0 + dt_1 / dt)) # There are other ways of estimating the LTE norm. norm_d = numpy.sqrt(inner(d, d) / u_max**2) # Get next step size. dt1 = dt0 * (eps / norm_d)**(1.0/3.0) else: dt1 = dt0 return u1, p1, dudt1, dt1
def F( u, v, kappa, rho, cp, convection, source, r, neumann_bcs, robin_bcs, my_dx, my_ds, stabilization, ): """ Compute .. math:: F(u) = \\int_\\Omega \\kappa r \\langle\\nabla u, \\nabla \\frac{v}{\\rho c_p}\\rangle \\, 2\\pi \\, \\text{d}x + \\int_\\Omega \\langle c, \\nabla u\\rangle v \\, 2\\pi r\\,\\text{d}x - \\int_\\Omega \\frac{1}{\\rho c_p} f v \\, 2\\pi r \\,\\text{d}x\\\\ - \\int_\\Gamma r \\kappa \\langle n, \\nabla T\\rangle v \\frac{1}{\\rho c_p} 2\\pi \\,\\text{d}s - \\int_\\Gamma r \\kappa \\alpha (u - u_0) v \\frac{1}{\\rho c_p} \\, 2\\pi \\,\\text{d}s, used for time-stepping .. math:: u' = F(u). """ rho_cp = rho * cp F0 = kappa * r * dot(grad(u), grad(v / rho_cp)) * 2 * pi * my_dx # F -= dot(b, grad(u)) * v * 2*pi*r * dx_workpiece(0) if convection is not None: c = as_vector([convection[0], convection[1]]) F0 += dot(c, grad(u)) * v * 2 * pi * r * my_dx # Joule heat F0 -= source * v / rho_cp * 2 * pi * r * my_dx # Neumann boundary conditions for k, n_grad_T in neumann_bcs.items(): F0 -= r * kappa * n_grad_T * v / rho_cp * 2 * pi * my_ds(k) # Robin boundary conditions for k, value in robin_bcs.items(): alpha, u0 = value F0 -= r * kappa * alpha * (u - u0) * v / rho_cp * 2 * pi * my_ds(k) if stabilization == "supg": # Add SUPG stabilization. assert convection is not None # TODO u_t? R = ( -div(kappa * r * grad(u)) / rho_cp * 2 * pi + dot(c, grad(u)) * 2 * pi * r - source / rho_cp * 2 * pi * r ) mesh = v.function_space().mesh() element_degree = v.ufl_element().degree() tau = stab.supg(mesh, convection, kappa, element_degree) F0 += R * tau * dot(convection, grad(v)) * my_dx else: assert stabilization is None return F0
def ab2tr_step0(u0, P, f, # right-hand side rho, mu, dudt_bcs=[], p_bcs=[], eps=1.0e-4, # relative error tolerance verbose=True ): # Make sure that the initial velocity is divergence-free. alpha = norm(u0, 'Hdiv0') if abs(alpha) > DOLFIN_EPS: warn('Initial velocity not divergence-free (||u||_div = %e).' % alpha ) # Get the initial u0' and p0 by solving the linear equation system # # [M C] [u0'] [f0 - (K+N(u0)u0)] # [C^T 0] [p0 ] = [ g0' ], # # i.e., # # rho u0' + nabla(p0) = f0 + mu\Delta(u0) - rho u0.nabla(u0), # div(u0') = 0. # W = u0.function_space() WP = W*P # Translate the boundary conditions into product space. See # <http://fenicsproject.org/qa/703/boundary-conditions-in-product-space>. dudt_bcs_new = [] for dudt_bc in dudt_bcs: dudt_bcs_new.append(DirichletBC(WP.sub(0), dudt_bc.value(), dudt_bc.user_sub_domain())) p_bcs_new = [] for p_bc in p_bcs: p_bcs_new.append(DirichletBC(WP.sub(1), p_bc.value(), p_bc.user_sub_domain())) new_bcs = dudt_bcs_new + p_bcs_new (u, p) = TrialFunctions(WP) (v, q) = TestFunctions(WP) #a = rho * dot(u, v) * dx + dot(grad(p), v) * dx \ a = rho * inner(u, v) * dx - p * div(v) * dx \ - div(u) * q * dx L = _rhs_weak(u0, v, f, rho, mu) A, b = assemble_system(a, L, new_bcs) # Similar preconditioner as for the Stokes problem. # TODO implement something better! prec = rho * inner(u, v) * dx \ - p*q*dx M, _ = assemble_system(prec, L, new_bcs) solver = KrylovSolver('gmres', 'amg') solver.parameters['monitor_convergence'] = verbose solver.parameters['report'] = verbose solver.parameters['absolute_tolerance'] = 0.0 solver.parameters['relative_tolerance'] = 1.0e-6 solver.parameters['maximum_iterations'] = 10000 # Associate operator (A) and preconditioner matrix (M) solver.set_operators(A, M) #solver.set_operator(A) # Solve up = Function(WP) solver.solve(up.vector(), b) # Get sub-functions dudt0, p0 = up.split() # Choosing the first step size for the trapezoidal rule can be tricky. # Chapters 2.7.4a, 2.7.4e of the book # # Incompressible flow and the finite element method, # volume 1: advection-diffusion; # P.M. Gresho, R.L. Sani, # # give some hints. # # eps ... relative error tolerance # tau ... estimate of the initial 'time constant' tau = None if tau: dt0 = tau * eps**(1.0/3.0) else: # Choose something 'reasonably small'. dt0 = 1.0e-3 # Alternative: # Use a dissipative scheme like backward Euler or BDF2 for the first # couple of steps. This makes sure that noisy initial data is damped # out. return dudt0, p0, dt0
def run_with_params(Tb, mu_value, k_s, path): run_time_init = clock() mesh = BoxMesh(Point(0.0, 0.0, 0.0), Point(mesh_width, mesh_width, mesh_height), nx, ny, nz) pbc = PeriodicBoundary() WE = VectorElement('CG', mesh.ufl_cell(), 2) SE = FiniteElement('CG', mesh.ufl_cell(), 1) WSSS = FunctionSpace(mesh, MixedElement(WE, SE, SE, SE), constrained_domain=pbc) # W = FunctionSpace(mesh, WE, constrained_domain=pbc) # S = FunctionSpace(mesh, SE, constrained_domain=pbc) W = WSSS.sub(0).collapse() S = WSSS.sub(1).collapse() temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273] temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element()) mu_a = mu_value # this was taken from the Blankenbach paper, can change Ep = b / temp_prof.delta mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a # TODO: verify exponentiation Ra = rho_0 * alpha * g * temp_prof.delta * h ** 3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * temp_prof.delta * h ** 2 / mu_a tau = h / w0 p0 = mu_a * w0 / h log(mu_a, mu_bot, Ra, w0, p0) slip_vx = 1.6E-09 / w0 # Non-dimensional slip_velocity = Constant((slip_vx, 0.0, 0.0)) zero_slip = Constant((0.0, 0.0, 0.0)) time_step = 3.0E11 / tau * 2 dt = Constant(time_step) t_end = 3.0E15 / tau / 5.0 # Non-dimensional times u = Function(WSSS) # Instead of TrialFunctions, we use split(u) for our non-linear problem v, p, T, Tf = split(u) v_t, p_t, T_t, Tf_t = TestFunctions(WSSS) T0 = interpolate(temp_prof, S) mu_exp = Expression('exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)', Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0, element=S.ufl_element()) Tf0 = interpolate(temp_prof, S) mu = Function(S) v0 = Function(W) v_theta = (1.0 - theta) * v0 + theta * v T_theta = (1.0 - theta) * T0 + theta * T Tf_theta = (1.0 - theta) * Tf0 + theta * Tf # TODO: Verify forms r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v))) - div(v_t) * p - T * v_t[2]) * dx r_p = p_t * div(v) * dx heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt r_T = (T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta))) # TODO: Inner vs dot + (dt / Ra) * inner(grad(T_t), grad(T_theta)) - T_t * heat_transfer) * dx v_melt = Function(W) z_hat = Constant((0.0, 0.0, 1.0)) # TODO: inner -> dot, take out Tf_t r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta))) + Tf_t * heat_transfer) * dx r = r_v + r_p + r_T + r_Tf bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top) bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom) bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back) bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front) bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top) bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom) bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom) bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1] t = 0 count = 0 files = DefaultDictByKey(partial(create_xdmf, path)) while t < t_end: mu.interpolate(mu_exp) rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0)) deltarho = rhosolid - rho_melt # TODO: project (accuracy) vs interpolate assign(v_melt, project(v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0, W)) # TODO: Written out one step later? # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0) # TODO: use nP after to avoid projection? solve(r == 0, u, bcs) nV, nP, nT, nTf = u.split() # TODO: write with Tf, ... etc if count % output_every == 0: time_left(count, t_end / time_step, run_time_init) # TODO: timestep vs dt # TODO: Make sure all writes are to the same function for each time step files['T_fluid'].write(nTf, t) files['p'].write(nP, t) files['v_solid'].write(nV, t) files['T_solid'].write(nT, t) files['mu'].write(mu, t) files['v_melt'].write(v_melt, t) files['gradp'].write(project(grad(nP), W), t) files['rho'].write(project(rhosolid, S), t) files['Tf_grad'].write(project(grad(Tf), W), t) files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t) files['ht'].write(project(heat_transfer, S), t) assign(T0, nT) assign(v0, nV) assign(Tf0, nTf) t += time_step count += 1 log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format(mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
def _evaluateLocalEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, epsilon=1e-5): """Evaluation of patch local equilibrated estimator.""" # prepare numerical flux and f sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f) # ################### # ## MIXED PROBLEM ## # ################### # get setup data for mixed problem V = w[mu]._fefunc.function_space() mesh = V.mesh() mesh.init() degree = element_degree(w[mu]._fefunc) # data for nodal bases V_dm = V.dofmap() V_dofs = dict([(i, V_dm.cell_dofs(i)) for i in range(mesh.num_cells())]) V1 = FunctionSpace(mesh, 'CG', 1) # V1 is to define nodal base functions phi_z = Function(V1) phi_coeffs = np.ndarray(V1.dim()) vertex_dof_map = V1.dofmap().vertex_to_dof_map(mesh) # vertex_dof_map = vertex_to_dof_map(V1) dof_list = vertex_dof_map.tolist() # DG0 localisation DG0 = FunctionSpace(mesh, 'DG', 0) DG0_dofs = dict([(c.index(),DG0.dofmap().cell_dofs(c.index())[0]) for c in cells(mesh)]) dg0 = TestFunction(DG0) # characteristic function of patch xi_z = Function(DG0) xi_coeffs = np.ndarray(DG0.dim()) # mesh data h = CellSize(mesh) n = FacetNormal(mesh) cf = CellFunction('size_t', mesh) # setup error estimator vector eq_est = np.zeros(DG0.dim()) # setup global equilibrated flux vector DG = VectorFunctionSpace(mesh, "DG", degree) DG_dofmap = DG.dofmap() # define form functions tau = TrialFunction(DG) v = TestFunction(DG) # define global tau tau_global = Function(DG) tau_global.vector()[:] = 0.0 # iterate vertices for vertex in vertices(mesh): # get patch cell indices vid = vertex.index() patch_cid, FF_inner, FF_boundary = get_vertex_patch(vid, mesh, layers=1) # set nodal base function phi_coeffs[:] = 0 phi_coeffs[dof_list.index(vid)] = 1 phi_z.vector()[:] = phi_coeffs # set characteristic function and mark patch cf.set_all(0) xi_coeffs[:] = 0 for cid in patch_cid: xi_coeffs[DG0_dofs[int(cid)]] = 1 cf[int(cid)] = 1 xi_z.vector()[:] = xi_coeffs # determine local dofs lDG_cell_dofs = dict([(cid, DG_dofmap.cell_dofs(cid)) for cid in patch_cid]) lDG_dofs = [cd.tolist() for cd in lDG_cell_dofs.values()] lDG_dofs = list(iter.chain(*lDG_dofs)) # print "\nlocal DG subspace has dimension", len(lDG_dofs), "degree", degree, "cells", len(patch_cid), patch_cid # print "local DG_cell_dofs", lDG_cell_dofs # print "local DG_dofs", lDG_dofs # create patch measures dx = Measure('dx')[cf] dS = Measure('dS')[FF_inner] # define forms alpha = Constant(1 / epsilon) / h a = inner(tau,v) * phi_z * dx(1) + alpha * div(tau) * div(v) * dx(1) + avg(alpha) * jump(tau,n) * jump(v,n) * dS(1)\ + avg(alpha) * jump(xi_z * tau,n) * jump(v,n) * dS(2) L = -alpha * (div(sigma_mu) + f) * div(v) * phi_z * dx(1)\ - avg(alpha) * jump(sigma_mu,n) * jump(v,n) * avg(phi_z)*dS(1) # print "L2 f + div(sigma)", assemble((f + div(sigma)) * (f + div(sigma)) * dx(0)) # assemble forms lhs = assemble(a, form_compiler_parameters={'quadrature_degree': quadrature_degree}) rhs = assemble(L, form_compiler_parameters={'quadrature_degree': quadrature_degree}) # convert DOLFIN representation to scipy sparse arrays rows, cols, values = lhs.data() lhsA = sps.csr_matrix((values, cols, rows)).tocoo() # slice sparse matrix and solve linear problem lhsA = coo_submatrix_pull(lhsA, lDG_dofs, lDG_dofs) lx = spsolve(lhsA, rhs.array()[lDG_dofs]) # print ">>> local solution lx", type(lx), lx local_tau = Function(DG) local_tau.vector()[lDG_dofs] = lx # print "div(tau)", assemble(inner(div(local_tau),div(local_tau))*dx(1)) # add up local fluxes tau_global.vector()[lDG_dofs] += lx # evaluate estimator # maybe TODO: re-define measure dx eq_est = assemble( inner(tau_global, tau_global) * dg0 * (dx(0)+dx(1)),\ form_compiler_parameters={'quadrature_degree': quadrature_degree}) # reorder according to cell ids eq_est = eq_est[DG0_dofs.values()].array() global_est = np.sqrt(np.sum(eq_est)) # eq_est_global = assemble( inner(tau_global, tau_global) * (dx(0)+dx(1)), form_compiler_parameters={'quadrature_degree': quadrature_degree} ) # global_est2 = np.sqrt(np.sum(eq_est_global)) return global_est, FlatVector(np.sqrt(eq_est))#, tau_global
def _evaluateGlobalMixedEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, vectorspace_type='BDM'): """Evaluation of global mixed equilibrated estimator.""" # set quadrature degree # quadrature_degree_old = parameters["form_compiler"]["quadrature_degree"] # parameters["form_compiler"]["quadrature_degree"] = quadrature_degree # logger.debug("residual quadrature order = " + str(quadrature_degree)) # prepare numerical flux and f sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f) # ################### # ## MIXED PROBLEM ## # ################### # get setup data for mixed problem V = w[mu]._fefunc.function_space() mesh = V.mesh() degree = element_degree(w[mu]._fefunc) # create function spaces DG0 = FunctionSpace(mesh, 'DG', 0) DG0_dofs = [DG0.dofmap().cell_dofs(c.index())[0] for c in cells(mesh)] RT = FunctionSpace(mesh, vectorspace_type, degree) W = RT * DG0 # setup boundary conditions # bcs = pde.create_dirichlet_bcs(W.sub(1)) # debug === # from dolfin import DOLFIN_EPS, DirichletBC # def boundary(x): # return x[0] < DOLFIN_EPS or x[0] > 1.0 + DOLFIN_EPS or x[1] < DOLFIN_EPS or x[1] > 1.0 + DOLFIN_EPS # bcs = [DirichletBC(W.sub(1), Constant(0.0), boundary)] # === debug # create trial and test functions (sigma, u) = TrialFunctions(W) (tau, v) = TestFunctions(W) # define variational form a_eq = (dot(sigma, tau) + div(tau) * u + div(sigma) * v) * dx L_eq = (- f_mu * v + dot(sigma_mu, tau)) * dx # compute solution w_eq = Function(W) solve(a_eq == L_eq, w_eq) (sigma_mixed, u_mixed) = w_eq.split() # ############################# # ## EQUILIBRATION ESTIMATOR ## # ############################# # evaluate error estimator dg0 = TestFunction(DG0) eta_mu = inner(sigma_mu, sigma_mu) * dg0 * dx eta_T = assemble(eta_mu, form_compiler_parameters={'quadrature_degree': quadrature_degree}) eta_T = np.array([sqrt(e) for e in eta_T]) # evaluate global error eta = sqrt(sum(i**2 for i in eta_T)) # reorder array entries for local estimators eta_T = eta_T[DG0_dofs] # restore quadrature degree # parameters["form_compiler"]["quadrature_degree"] = quadrature_degree_old return eta, FlatVector(eta_T)
def momentum_equation(u, v, p, f, rho, mu, stabilization=None, dx=dx): '''Weak form of the momentum equation. ''' assert rho > 0.0 assert mu > 0.0 # Skew-symmetric formulation. # Don't include the boundary term # # - mu *inner(r*grad(u2)*n , v2 ) * 2*pi*ds. # # This effectively means that at all boundaries where no sufficient # Dirichlet-conditions are posed, we assume grad(u)*n to vanish. # # The original term # u2[0]/(r*r) * v2[0] # doesn't explode iff u2[0]~r and v2[0]~r at r=0. Hence, we need to enforce # homogeneous Dirichlet-conditions for n.u at r=0. This corresponds to no # flow in normal direction through the symmetry axis -- makes sense. # When using the 2*pi*r weighting, we can even be a bit lax on the # enforcement on u2[0]. # # For this to be well defined, u[0]/r and u[2]/r must be bounded for r=0, # so u[0]~u[2]~r must hold. This either needs to be enforced in the # boundary conditions (homogeneous Dirichlet for u[0], u[2] at r=0) or must # follow from the dynamics of the system. # # TODO some more explanation for the following lines of code r = Expression('x[0]', degree=1, domain=v.function_space().mesh()) F = rho * 0.5 * (dot(grad(u) * u, v) - dot(grad(v) * u, u)) * 2*pi*r*dx \ + mu * inner(r * grad(u), grad(v)) * 2 * pi * dx \ + mu * u[0] / r * v[0] * 2 * pi * dx \ - dot(f, v) * 2 * pi * r * dx if p: F += (p.dx(0) * v[0] + p.dx(1) * v[1]) * 2 * pi * r * dx if len(u) == 3: F += rho * (-u[2] * u[2] * v[0] + u[0] * u[2] * v[2]) \ * 2 * pi * dx F += mu * u[2] / r * v[2] * 2 * pi * dx if stabilization: if stabilization == 'SUPG': # TODO check this part of the code # # SUPG stabilization has the form # # <R, tau*grad(v)*u[-1]> # # with R being the residual in strong form. The choice of the tau # is subject to research. tau = stab.supg2(u.function_space().W.mesh(), u, mu / rho, u.function_space().ufl_element().degree() ) # We need to deal with the term # # \int mu * (u2[0]/r**2, 0) * dot(R, grad(v2)*b_tau) 2*pi*r*dx # # somehow. Unfortunately, it's not easy to construct (u2[0]/r**2, # 0), cf. <https://answers.launchpad.net/dolfin/+question/228353>. # Strong residual: R = rho * grad(u) * u * 2 * pi * r \ - mu * div(r * grad(u)) * 2 * pi \ - f * 2 * pi * r if p: R += (p.dx(0) * v[0] + p.dx(1) * v[1]) \ * 2 * pi * r * dx gv = tau * grad(v) * u F += dot(R, gv) * dx # Manually add the parts of the residual which couldn't be cleanly # implemented above. F += mu * u[0] / r * 2 * pi * gv[0] * dx if u.function_space().num_sub_spaces() == 3: F += rho * (-u[2] * u[2] * gv[0] + u[0] * u[2] * gv[2]) \ * 2 * pi * dx F += mu * u[2] / r * gv[2] * 2 * pi * dx else: raise ValueError('Illegal stabilization type.') return F
def RunJob(Tb, mu_value, path): runtimeInit = clock() tfile = File(path + '/t6t.pvd') mufile = File(path + "/mu.pvd") ufile = File(path + '/velocity.pvd') gradpfile = File(path + '/gradp.pvd') pfile = File(path + '/pstar.pvd') parameters = open(path + '/parameters', 'w', 0) vmeltfile = File(path + '/vmelt.pvd') rhofile = File(path + '/rhosolid.pvd') for name in dir(): ev = str(eval(name)) if name[0] != '_' and ev[0] != '<': parameters.write(name + ' = ' + ev + '\n') temp_values = [27. + 273, Tb + 273, 1300. + 273, 1305. + 273] dTemp = temp_values[3] - temp_values[0] temp_values = [x / dTemp for x in temp_values] # non dimensionalising temp mu_a = mu_value # this was taken from the blankenbach paper, can change.. Ep = b / dTemp mu_bot = exp(-Ep * (temp_values[3] * dTemp - 1573) + cc) * mu_a Ra = rho_0 * alpha * g * dTemp * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * dTemp * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h print(mu_a, mu_bot, Ra, w0, p0) vslipx = 1.6e-09 / w0 vslip = Constant((vslipx, 0.0)) # nondimensional noslip = Constant((0.0, 0.0)) dt = 3.E11 / tau tEnd = 3.E13 / tau # non-dimensionalising times class PeriodicBoundary(SubDomain): def inside(self, x, on_boundary): return left(x, on_boundary) def map(self, x, y): y[0] = x[0] - MeshWidth y[1] = x[1] pbc = PeriodicBoundary() class TempExp(Expression): def eval(self, value, x): if x[1] >= LAB(x): value[0] = temp_values[0] + (temp_values[1] - temp_values[0]) * (MeshHeight - x[1]) / (MeshHeight - LAB(x)) else: value[0] = temp_values[3] - (temp_values[3] - temp_values[2]) * (x[1]) / (LAB(x)) class FluidTemp(Expression): def eval(self, value, x): if value[0] < 1295: value[0] = 1295 mesh = RectangleMesh(Point(0.0, 0.0), Point(MeshWidth, MeshHeight), nx, ny) Svel = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Spre = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Stemp = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Smu = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Sgradp = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Srho = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) S0 = MixedFunctionSpace([Svel, Spre, Stemp]) u = Function(S0) v, p, T = split(u) v_t, p_t, T_t = TestFunctions(S0) T0 = interpolate(TempExp(), Stemp) muExp = Expression('exp(-Ep * (T_val * dTemp - 1573) + cc * x[2] / meshHeight)', Smu.ufl_element(), Ep=Ep, dTemp=dTemp, cc=cc, meshHeight=MeshHeight, T_val=T0) mu = interpolate(muExp, Smu) rhosolid = Function(Srho) deltarho = Function(Srho) v0 = Function(Svel) vmelt = Function(Svel) v_theta = (1. - theta)*v0 + theta*v T_theta = (1. - theta)*T + theta*T0 r_v = (inner(sym(grad(v_t)), 2.*mu*sym(grad(v))) \ - div(v_t)*p \ - T*v_t[1] )*dx r_p = p_t*div(v)*dx r_T = (T_t*((T - T0) \ + dt*inner(v_theta, grad(T_theta))) \ + (dt/Ra)*inner(grad(T_t), grad(T_theta)) )*dx # + k_s*(Tf-T_theta)*dt Tf = T0.interpolate(FluidTemp()) # Tf = T0.interpolate(Expression('value[0] >= 1295.0 ? value[0] : 1295.0')) # Tf.interpolate(Expression('value[0] >= 1295 ? value[0] : 1295')) # project(Expression('value[0] >= 1295 ? value[0] : 1295'), Tf) # Alex, a question for you: # can you see if there is a way to set Tf = T in regions where T >=1295 celsius # # 1295 celsius is my arbitrary choice for the LAB isotherm. In regions # where T < 1295 C, set Tf to be some constant for now, such as 1295 C. # Once we do this, then we can add in a term like that last line above where # it will only be non-zero when the solid temperature, T, is cooler than 1295 # can you do this? After this is done, we will then worry about a calculation # where we solve for Tf as a function of time in the regions cooler than 1295 C # Makes sense? If not, we can skype soon -- email me with questions # 3/19/16 r = r_v + r_p + r_T bcv0 = DirichletBC(S0.sub(0), noslip, top) bcv1 = DirichletBC(S0.sub(0), vslip, bottom) bcp0 = DirichletBC(S0.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(S0.sub(2), Constant(temp_values[0]), top) bct1 = DirichletBC(S0.sub(2), Constant(temp_values[3]), bottom) bcs = [bcv0, bcv1, bcp0, bct0, bct1] t = 0 count = 0 while (t < tEnd): solve(r == 0, u, bcs) t += dt nV, nP, nT = u.split() gp = grad(nP) rhosolid = rho_0 * (1 - alpha * (nT * dTemp - 1573)) deltarho = rhosolid - rhomelt yvec = Constant((0.0, 1.0)) vmelt = nV * w0 - darcy * (gp * p0 / h - deltarho * yvec * g) if (count % 100 == 0): pfile << nP ufile << nV tfile << nT mufile << mu gradpfile << project(grad(nP), Sgradp) mufile << project(mu * mu_a, Smu) rhofile << project(rhosolid, Srho) vmeltfile << project(vmelt, Svel) count += 1 assign(T0, nT) assign(v0, nV) mu.interpolate(muExp) print('Case mu=%g, Tb=%g complete.' % (mu_a, Tb), ' Run time =', clock() - runtimeInit, 's')
def _pressure_poisson(self, p1, p0, mu, ui, divu, p_bcs=None, p_n=None, rotational_form=False, tol=1.0e-10, verbose=True ): '''Solve the pressure Poisson equation - \Delta phi = -div(u), boundary conditions, for \nabla p = u. ''' P = p1.function_space() p = TrialFunction(P) q = TestFunction(P) a2 = dot(grad(p), grad(q)) * dx L2 = -divu * q * dx if p0: L2 += dot(grad(p0), grad(q)) * dx if p_n: n = FacetNormal(P.mesh()) L2 += dot(n, p_n) * q * ds if rotational_form: L2 -= mu * dot(grad(div(ui)), grad(q)) * dx if p_bcs: solve(a2 == L2, p1, bcs=p_bcs, solver_parameters={ 'linear_solver': 'iterative', 'symmetric': True, 'preconditioner': 'hypre_amg', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 100, 'monitor_convergence': verbose} }) else: # If we're dealing with a pure Neumann problem here (which is the # default case), this doesn't hurt CG if the system is consistent, # cf. # # Iterative Krylov methods for large linear systems, # Henk A. van der Vorst. # # And indeed, it is consistent: Note that # # <1, rhs> = \sum_i 1 * \int div(u) v_i # = 1 * \int div(u) \sum_i v_i # = \int div(u). # # With the divergence theorem, we have # # \int div(u) = \int_\Gamma n.u. # # The latter term is 0 iff inflow and outflow are exactly the same # at any given point in time. This corresponds with the # incompressibility of the liquid. # # In turn, this hints towards penetrable boundaries to require # Dirichlet conditions on the pressure. # A = assemble(a2) b = assemble(L2) # # In principle, the ILU preconditioner isn't advised here since it # might destroy the semidefiniteness needed for CG. # # The system is consistent, but the matrix has an eigenvalue 0. # This does not harm the convergence of CG, but when # preconditioning one has to take care that the preconditioner # preserves the kernel. ILU might destroy this (and the # semidefiniteness). With AMG, the coarse grid solves cannot be LU # then, so try Jacobi here. # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html> # prec = PETScPreconditioner('hypre_amg') PETScOptions.set('pc_hypre_boomeramg_relax_type_coarse', 'jacobi') solver = PETScKrylovSolver('cg', prec) solver.parameters['absolute_tolerance'] = 0.0 solver.parameters['relative_tolerance'] = tol solver.parameters['maximum_iterations'] = 100 solver.parameters['monitor_convergence'] = verbose # Create solver and solve system A_petsc = as_backend_type(A) b_petsc = as_backend_type(b) p1_petsc = as_backend_type(p1.vector()) solver.set_operator(A_petsc) try: solver.solve(p1_petsc, b_petsc) except RuntimeError as error: info('') # Check if the system is indeed consistent. # # If the right hand side is flawed (e.g., by round-off errors), # then it may have a component b1 in the direction of the null # space, orthogonal the image of the operator: # # b = b0 + b1. # # When starting with initial guess x0=0, the minimal achievable # relative tolerance is then # # min_rel_tol = ||b1|| / ||b||. # # If ||b|| is very small, which is the case when ui is almost # divergence-free, then min_rel_to may be larger than the # prescribed relative tolerance tol. # # Use this as a consistency check, i.e., bail out if # # tol < min_rel_tol = ||b1|| / ||b||. # # For computing ||b1||, we use the fact that the null space is # one-dimensional, i.e., b1 = alpha e, and # # e.b = e.(b0 + b1) = e.b1 = alpha ||e||^2, # # so alpha = e.b/||e||^2 and # # ||b1|| = |alpha| ||e|| = e.b / ||e|| # e = Function(P) e.interpolate(Constant(1.0)) evec = e.vector() evec /= norm(evec) alpha = b.inner(evec) normB = norm(b) info('Linear system convergence failure.') info(error.message) message = ('Linear system not consistent! ' '<b,e> = %g, ||b|| = %g, <b,e>/||b|| = %e, tol = %e.') \ % (alpha, normB, alpha/normB, tol) info(message) if tol < abs(alpha) / normB: info('\int div(u) = %e' % assemble(divu * dx)) #n = FacetNormal(Q.mesh()) #info('\int_Gamma n.u = %e' % assemble(dot(n, u)*ds)) #info('\int_Gamma u[0] = %e' % assemble(u[0]*ds)) #info('\int_Gamma u[1] = %e' % assemble(u[1]*ds)) ## Now plot the faulty u on a finer mesh (to resolve the ## quadratic trial functions). #fine_mesh = Q.mesh() #for k in range(1): # fine_mesh = refine(fine_mesh) #V1 = FunctionSpace(fine_mesh, 'CG', 1) #W1 = V1*V1 #uplot = project(u, W1) ##uplot = Function(W1) ##uplot.interpolate(u) #plot(uplot, title='u_tentative') #plot(uplot[0], title='u_tentative[0]') #plot(uplot[1], title='u_tentative[1]') plot(divu, title='div(u_tentative)') interactive() exit() raise RuntimeError(message) else: exit() raise RuntimeError('Linear system failed to converge.') except: exit() return
def step(self, dt, u1, p1, u, p0, u_bcs, p_bcs, f0=None, f1=None, verbose=True, tol=1.0e-10 ): # Some initial sanity checkups. assert dt > 0.0 # Define trial and test functions ui = Function(self.W) v = TestFunction(self.W) # Create functions # Define coefficients k = Constant(dt) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Compute tentative velocity step: # # F(u) = 0, # F(u) := rho (U0 + (u.\nabla)u) - mu \div(\nabla u) - f = 0. # with Message('Computing tentative velocity'): # TODO higher-order scheme for time integration # # For higher-order schemes, see # # A comparison of time-discretization/linearization approaches # for the incompressible Navier-Stokes equations; # Volker John, Gunar Matthies, Joachim Rang; # Comput. Methods Appl. Mech. Engrg. 195 (2006) 5995-6010; # <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JMR06.CMAME.pdf>. # F1 = self.rho * inner((ui - u[0])/k, v) * dx if abs(self.theta) > DOLFIN_EPS: # Implicit terms. if f1 is None: raise RuntimeError('Implicit schemes need right-hand side ' 'at target step (f1).') F1 -= self.theta * _rhs_weak(ui, v, f1, self.rho, self.mu) if abs(1.0 - self.theta) > DOLFIN_EPS: # Explicit terms. if f0 is None: raise RuntimeError('Explicit schemes need right-hand side ' 'at current step (f0).') F1 -= (1.0 - self.theta) \ * _rhs_weak(u[0], v, f0, self.rho, self.mu) if p0: F1 += dot(grad(p0), v) * dx #if stabilization: # tau = stab.supg2(V.mesh(), # u_1, # mu/rho, # V.ufl_element().degree() # ) # R = rho*(ui - u_1)/k # if abs(theta) > DOLFIN_EPS: # R -= theta * _rhs_strong(ui, f1, rho, mu) # if abs(1.0-theta) > DOLFIN_EPS: # R -= (1.0-theta) * _rhs_strong(u_1, f0, rho, mu) # if p_1: # R += grad(p_1) # # TODO use u_1 or ui here? # F1 += tau * dot(R, grad(v)*u_1) * dx # Get linearization and solve nonlinear system. # If the scheme is fully explicit (theta=0.0), then the system is # actually linear and only one Newton iteration is performed. J = derivative(F1, ui) # What is a good initial guess for the Newton solve? # Three choices come to mind: # # (1) the previous solution u_1, # (2) the intermediate solution from the previous step ui_1, # (3) the solution of the semilinear system # (u.\nabla(u) -> u_1.\nabla(u)). # # Numerical experiments with the Karman vortex street show that the # order of accuracy is (1), (3), (2). Typical norms would look like # # ||u - u_1 || = 1.726432e-02 # ||u - ui_1|| = 2.720805e+00 # ||u - u_e || = 5.921522e-02 # # Hence, use u_1 as initial guess. ui.assign(u[0]) # Wrap the solution in a try-catch block to make sure we call end() # if necessary. #problem = NonlinearVariationalProblem(F1, ui, u_bcs, J) #solver = NonlinearVariationalSolver(problem) solve( F1 == 0, ui, bcs=u_bcs, J=J, solver_parameters={ #'nonlinear_solver': 'snes', 'nonlinear_solver': 'newton', 'newton_solver': { 'maximum_iterations': 5, 'report': True, 'absolute_tolerance': tol, 'relative_tolerance': 0.0, 'linear_solver': 'iterative', ## The nonlinear term makes the problem generally ## nonsymmetric. #'symmetric': False, # If the nonsymmetry is too strong, e.g., if u_1 is # large, then AMG preconditioning might not work very # well. 'preconditioner': 'ilu', #'preconditioner': 'hypre_amg', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 1000, 'monitor_convergence': verbose} }}) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - with Message('Computing pressure correction'): # # The following is based on the update formula # # rho/dt (u_{n+1}-u*) + \nabla phi = 0 # # with # # phi = (p_{n+1} - p*) + chi*mu*div(u*) # # and div(u_{n+1})=0. One derives # # - \nabla^2 phi = rho/dt div(u_{n+1} - u*), # - n.\nabla phi = rho/dt n.(u_{n+1} - u*), # # In its weak form, this is # # \int \grad(phi).\grad(q) # = - rho/dt \int div(u*) q - rho/dt \int_Gamma n.(u_{n+1}-u*) q. # # If Dirichlet boundary conditions are applied to both u* and # u_{n+1} (the latter in the final step), the boundary integral # vanishes. # # Assume that on the boundary # L2 -= inner(n, rho/k (u_bcs - ui)) * q * ds # is zero. This requires the boundary conditions to be set for # ui as well as u_final. # This creates some problems if the boundary conditions are # supposed to remain 'free' for the velocity, i.e., no Dirichlet # conditions in normal direction. In that case, one needs to # specify Dirichlet pressure conditions. # rotational_form = False self._pressure_poisson(p1, p0, self.mu, ui, divu=Constant(self.rho/dt)*div(ui), p_bcs=p_bcs, rotational_form=rotational_form, tol=tol, verbose=verbose ) #plot(p - phi, title='p-phi') #plot(ui, title='u intermediate') #plot(f, title='f') ##plot(ui[1], title='u intermediate[1]') #plot(div(ui), title='div(u intermediate)') #plot(phi, title='phi') #interactive() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Velocity correction. # U = U0 - dt/rho \nabla p. with Message('Computing velocity correction'): u2 = TrialFunction(self.W) a3 = inner(u2, v) * dx if p0: phi = Function(self.P) phi.assign(p1) phi -= p0 else: phi = p1 if rotational_form: phi += self.mu * div(ui) L3 = inner(ui, v) * dx \ - k/self.rho * inner(grad(phi), v) * dx solve(a3 == L3, u1, bcs=u_bcs, solver_parameters={ 'linear_solver': 'iterative', 'symmetric': True, 'preconditioner': 'jacobi', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 100, 'monitor_convergence': verbose} }) #u = project(ui - k/rho * grad(phi), V) #print '||u||_div = %e' % norm(u, 'Hdiv0') #uu = TrialFunction(Q) #vv = TestFunction(Q) #div_u = Function(Q) #solve(uu*vv*dx == div(u)*vv*dx, div_u, # #bcs=DirichletBC(Q, 0.0, 'on_boundary') # ) #plot(div_u, title='div(u)') #interactive() return
def solve(W, P, mu, u_bcs, p_bcs, f, verbose=True, tol=1.0e-10 ): # Some initial sanity checks. assert mu > 0.0 WP = MixedFunctionSpace([W, P]) # Translate the boundary conditions into the product space. # This conditional loop is able to deal with conditions of the kind # # DirichletBC(W.sub(1), 0.0, right_boundary) # new_bcs = [] for k, bcs in enumerate([u_bcs, p_bcs]): for bc in bcs: space = bc.function_space() C = space.component() if len(C) == 0: new_bcs.append(DirichletBC(WP.sub(k), bc.value(), bc.domain_args[0])) elif len(C) == 1: new_bcs.append(DirichletBC(WP.sub(k).sub(int(C[0])), bc.value(), bc.domain_args[0])) else: raise RuntimeError('Illegal number of subspace components.') # Define variational problem (u, p) = TrialFunctions(WP) (v, q) = TestFunctions(WP) # Build system. # The sign of the div(u)-term is somewhat arbitrary since the right-hand # side is 0 here. We can either make the system symmetric or positive- # definite. # On a second note, we have # # \int grad(p).v = - \int p * div(v) + \int_\Gamma p n.v. # # Since, we have either p=0 or n.v=0 on the boundary, we could as well # replace the term dot(grad(p), v) by -p*div(v). # a = mu * inner(grad(u), grad(v))*dx \ - p * div(v) * dx \ - q * div(u) * dx #a = mu * inner(grad(u), grad(v))*dx + dot(grad(p), v) * dx \ # - div(u) * q * dx L = dot(f, v)*dx A, b = assemble_system(a, L, new_bcs) if has_petsc(): # For an assortment of preconditioners, see # # Performance and analysis of saddle point preconditioners # for the discrete steady-state Navier-Stokes equations; # H.C. Elman, D.J. Silvester, A.J. Wathen; # Numer. Math. (2002) 90: 665-688; # <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>. # # Set up field split. W = SubSpace(WP, 0) P = SubSpace(WP, 1) u_dofs = W.dofmap().dofs() p_dofs = P.dofmap().dofs() prec = PETScPreconditioner() prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p']) PETScOptions.set('pc_type', 'fieldsplit') PETScOptions.set('pc_fieldsplit_type', 'additive') PETScOptions.set('fieldsplit_u_pc_type', 'lu') PETScOptions.set('fieldsplit_p_pc_type', 'jacobi') ## <http://scicomp.stackexchange.com/questions/7288/which-preconditioners-and-solver-in-petsc-for-indefinite-symmetric-systems-sho> #PETScOptions.set('pc_type', 'fieldsplit') ##PETScOptions.set('pc_fieldsplit_type', 'schur') ##PETScOptions.set('pc_fieldsplit_schur_fact_type', 'upper') #PETScOptions.set('pc_fieldsplit_detect_saddle_point') ##PETScOptions.set('fieldsplit_u_pc_type', 'lsc') ##PETScOptions.set('fieldsplit_u_ksp_type', 'preonly') #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('fieldsplit_u_pc_type', 'hypre') #PETScOptions.set('fieldsplit_u_ksp_type', 'preonly') #PETScOptions.set('fieldsplit_p_pc_type', 'jacobi') #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly') ## From PETSc/src/ksp/ksp/examples/tutorials/ex42-fsschur.opts: #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('pc_fieldsplit_type', 'SCHUR') #PETScOptions.set('pc_fieldsplit_schur_fact_type', 'UPPER') #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly') #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi') ## From ## ## Composable Linear Solvers for Multiphysics; ## J. Brown, M. Knepley, D.A. May, L.C. McInnes, B. Smith; ## <http://www.computer.org/csdl/proceedings/ispdc/2012/4805/00/4805a055-abs.html>; ## <http://www.mcs.anl.gov/uploads/cels/papers/P2017-0112.pdf>. ## #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('pc_fieldsplit_type', 'schur') #PETScOptions.set('pc_fieldsplit_schur_factorization_type', 'upper') ## #PETScOptions.set('fieldsplit_u_ksp_type', 'cg') #PETScOptions.set('fieldsplit_u_ksp_rtol', 1.0e-6) #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi') #PETScOptions.set('fieldsplit_u_sub_pc_type', 'cholesky') ## #PETScOptions.set('fieldsplit_p_ksp_type', 'fgmres') #PETScOptions.set('fieldsplit_p_ksp_constant_null_space') #PETScOptions.set('fieldsplit_p_pc_type', 'lsc') ## #PETScOptions.set('fieldsplit_p_lsc_ksp_type', 'cg') #PETScOptions.set('fieldsplit_p_lsc_ksp_rtol', 1.0e-2) #PETScOptions.set('fieldsplit_p_lsc_ksp_constant_null_space') ##PETScOptions.set('fieldsplit_p_lsc_ksp_converged_reason') #PETScOptions.set('fieldsplit_p_lsc_pc_type', 'bjacobi') #PETScOptions.set('fieldsplit_p_lsc_sub_pc_type', 'icc') # Create Krylov solver with custom preconditioner. solver = PETScKrylovSolver('gmres', prec) solver.set_operator(A) else: # Use the preconditioner as recommended in # <http://fenicsproject.org/documentation/dolfin/dev/python/demo/pde/stokes-iterative/python/documentation.html>, # # prec = inner(grad(u), grad(v))*dx - p*q*dx # # although it doesn't seem to be too efficient. # The sign on the last term doesn't matter. prec = mu * inner(grad(u), grad(v))*dx \ - p*q*dx M, _ = assemble_system(prec, L, new_bcs) #solver = KrylovSolver('tfqmr', 'amg') solver = KrylovSolver('gmres', 'amg') solver.set_operators(A, M) solver.parameters['monitor_convergence'] = verbose solver.parameters['report'] = verbose solver.parameters['absolute_tolerance'] = 0.0 solver.parameters['relative_tolerance'] = tol solver.parameters['maximum_iterations'] = 500 # Solve up = Function(WP) solver.solve(up.vector(), b) # Get sub-functions u, p = up.split() return u, p
def __init__(self, mesh, Vh, t_init, t_final, t_1, dt, wind_velocity, gls_stab, Prior): self.mesh = mesh self.Vh = Vh self.t_init = t_init self.t_final = t_final self.t_1 = t_1 self.dt = dt self.sim_times = np.arange(self.t_init, self.t_final+.5*self.dt, self.dt) u = dl.TrialFunction(Vh[STATE]) v = dl.TestFunction(Vh[STATE]) kappa = dl.Constant(.001) dt_expr = dl.Constant(self.dt) r_trial = u + dt_expr*( -dl.div(kappa*dl.nabla_grad(u))+ dl.inner(wind_velocity, dl.nabla_grad(u)) ) r_test = v + dt_expr*( -dl.div(kappa*dl.nabla_grad(v))+ dl.inner(wind_velocity, dl.nabla_grad(v)) ) h = dl.CellSize(mesh) vnorm = dl.sqrt(dl.inner(wind_velocity, wind_velocity)) if gls_stab: tau = dl.Min((h*h)/(dl.Constant(2.)*kappa), h/vnorm ) else: tau = dl.Constant(0.) self.M = dl.assemble( dl.inner(u,v)*dl.dx ) self.M_stab = dl.assemble( dl.inner(u, v+tau*r_test)*dl.dx ) self.Mt_stab = dl.assemble( dl.inner(u+tau*r_trial,v)*dl.dx ) Nvarf = (dl.inner(kappa *dl.nabla_grad(u), dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(u))*v )*dl.dx Ntvarf = (dl.inner(kappa *dl.nabla_grad(v), dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(v))*u )*dl.dx self.N = dl.assemble( Nvarf ) self.Nt = dl.assemble(Ntvarf) stab = dl.assemble( tau*dl.inner(r_trial, r_test)*dl.dx) self.L = self.M + dt*self.N + stab self.Lt = self.M + dt*self.Nt + stab boundaries = dl.FacetFunction("size_t", mesh) boundaries.set_all(0) class InsideBoundary(dl.SubDomain): def inside(self,x,on_boundary): x_in = x[0] > dl.DOLFIN_EPS and x[0] < 1 - dl.DOLFIN_EPS y_in = x[1] > dl.DOLFIN_EPS and x[1] < 1 - dl.DOLFIN_EPS return on_boundary and x_in and y_in Gamma_M = InsideBoundary() Gamma_M.mark(boundaries,1) ds_marked = dl.Measure("ds", subdomain_data=boundaries) self.Q = dl.assemble( self.dt*dl.inner(u, v) * ds_marked(1) ) self.Prior = Prior if dlversion() <= (1,6,0): self.solver = dl.PETScLUSolver() else: self.solver = dl.PETScLUSolver(self.mesh.mpi_comm()) self.solver.set_operator(self.L) if dlversion() <= (1,6,0): self.solvert = dl.PETScLUSolver() else: self.solvert = dl.PETScLUSolver(self.mesh.mpi_comm()) self.solvert.set_operator(self.Lt) self.ud = self.generate_vector(STATE) self.noise_variance = 0 # Part of model public API self.gauss_newton_approx = False
def get_stokessysmats(V, Q, nu=None, bccontrol=False, cbclist=None, cbshapefuns=None): """ Assembles the system matrices for Stokes equation in mixed FEM formulation, namely .. math:: \\begin{bmatrix} A & -J' \\\\ J & 0 \\end{bmatrix}\ \\colon V \\times Q \\to V' \\times Q' as the discrete representation of .. math:: \\begin{bmatrix} -\\Delta & \\text{grad} \\\\ \ \\text{div} & 0 \\end{bmatrix} plus the velocity and pressure mass matrices for a given trial and test space W = V * Q not considering boundary conditions. Parameters ---------- V : dolfin.VectorFunctionSpace Fenics VectorFunctionSpace for the velocity Q : dolfin.FunctionSpace Fenics FunctionSpace for the pressure nu : float, optional viscosity parameter - defaults to 1 bccontrol : boolean, optional whether boundary control (via penalized Robin conditions) is applied, defaults to `False` cbclist : list, optional list of dolfin's Subdomain classes describing the control boundaries cbshapefuns : list, optional list of spatial shape functions of the control boundaries Returns ------- stokesmats, dictionary a dictionary with the following keys: * ``M``: the mass matrix of the velocity space, * ``A``: the stiffness matrix \ :math:`\\nu \\int_\\Omega (\\nabla \\phi_i, \\nabla \\phi_j)` * ``JT``: the gradient matrix, * ``J``: the divergence matrix, and * ``MP``: the mass matrix of the pressure space * ``Apbc``: (N, N) sparse matrix, \ the contribution of the Robin conditions to `A` \ :math:`\\nu \\int_\\Gamma (\\phi_i, \\phi_j)` * ``Bpbc``: (N, k) sparse matrix, the input matrix of the Robin \ conditions :math:`\\nu \\int_\\Gamma (\\phi_i, g_k)`, \ where :math:`g_k` is the shape function associated with the \ j-th control boundary segment """ u = dolfin.TrialFunction(V) p = dolfin.TrialFunction(Q) v = dolfin.TestFunction(V) q = dolfin.TestFunction(Q) if nu is None: nu = 1 print('No viscosity provided -- we set `nu=1`') ma = inner(u, v) * dx mp = inner(p, q) * dx aa = nu * inner(grad(u), grad(v)) * dx grada = div(v) * p * dx diva = q * div(u) * dx # Assemble system M = dolfin.assemble(ma) A = dolfin.assemble(aa) Grad = dolfin.assemble(grada) Div = dolfin.assemble(diva) MP = dolfin.assemble(mp) # Convert DOLFIN representation to scipy arrays Ma = mat_dolfin2sparse(M) MPa = mat_dolfin2sparse(MP) Aa = mat_dolfin2sparse(A) JTa = mat_dolfin2sparse(Grad) Ja = mat_dolfin2sparse(Div) stokesmats = {'M': Ma, 'A': Aa, 'JT': JTa, 'J': Ja, 'MP': MPa} if bccontrol: amatrobl, bmatrobl = [], [] mesh = V.mesh() for bc, bcfun in zip(cbclist, cbshapefuns): # get an instance of the subdomain class Gamma = bc() # bparts = dolfin.MeshFunction('size_t', mesh, # mesh.topology().dim() - 1) boundaries = dolfin.MeshFunction("size_t", mesh, mesh.topology().dim()-1) boundaries.set_all(0) Gamma.mark(boundaries, 1) ds = dolfin.Measure('ds', domain=mesh, subdomain_data=boundaries) # Gamma.mark(bparts, 0) # Robin boundary form arob = dolfin.inner(u, v) * ds(1) # , subdomain_data=bparts) brob = dolfin.inner(v, bcfun) * ds(1) # , subdomain_data=bparts) amatrob = dolfin.assemble(arob) # , exterior_facet_domains=bparts) bmatrob = dolfin.assemble(brob) # , exterior_facet_domains=bparts) amatrob = mat_dolfin2sparse(amatrob) amatrob.eliminate_zeros() amatrobl.append(amatrob) bmatrobl.append(bmatrob.get_local().reshape((V.dim(), 1))) amatrob = amatrobl[0] for amatadd in amatrobl[1:]: amatrob = amatrob + amatadd bmatrob = np.hstack(bmatrobl) stokesmats.update({'amatrob': amatrob, 'bmatrob': bmatrob}) return stokesmats
def _rhs_strong(u, f, rho, mu): '''Right-hand side of the Navier--Stokes momentum equation in strong form. ''' return f \ - mu * div(grad(u)) \ - rho * (grad(u)*u + 0.5*div(u)*u)