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 setup_NSu(u, v, u_, p_, bcs_NSu, u_1, p_1, phi_, rho_, rho_1, g_, M_, nu_, rho_e_, V_, dt, drho, sigma_bar, eps, dveps, grav, enable_PF, enable_EC): """ Set up the Navier-Stokes subproblem. """ # Crank-Nicolson velocity # u_CN = 0.5*(u_1 + u) F_predict = ( 1. / dt * df.sqrt(rho_) * df.dot(df.sqrt(rho_) * u - df.sqrt(rho_1) * u_1, v) * df.dx # + rho_*df.inner(df.grad(u), df.outer(u_1, v))*df.dx # + 2*nu_*df.inner(df.sym(df.grad(u)), df.grad(v))*df.dx # - p_1 * df.div(v)*df.dx # + df.div(u)*q*df.dx + rho_ * df.dot(df.dot(u_1, df.nabla_grad(u)), v) * df.dx + 2 * nu_ * df.inner(df.sym(df.grad(u)), df.sym(df.grad(v))) * df.dx - p_1 * df.div(v) * df.dx - df.dot(rho_ * grav, v) * df.dx) phi_filtered = unit_interval_filter(phi_) if enable_PF: F_predict += -drho * M_ * df.dot( df.dot(df.nabla_grad(g_), df.nabla_grad(u)), v) * df.dx F_predict += -sigma_bar * eps * df.inner( df.outer(df.grad(phi_filtered), df.grad(phi_filtered)), df.grad(v)) * df.dx if enable_EC and rho_e_ != 0: F_predict += rho_e_ * df.dot(df.grad(V_), v) * df.dx if enable_PF and enable_EC: F_predict += dveps * df.dot(df.grad(phi_filtered), v) * df.dot( df.grad(V_), df.grad(V_)) * df.dx # a1, L1 = df.lhs(F_predict), df.rhs(F_predict) F_correct = (df.inner(u - u_, v) * df.dx + dt / rho_ * df.inner(df.grad(p_ - p_1), v) * df.dx) # a3 = df.dot(u, v)*df.dx # L3 = df.dot(u_, v)*df.dx - dt*df.dot(df.grad(p_), v)*df.dx # a3, L3 = df.lhs(F_correct), df.rhs(F_correct) solver = dict() # solver["a1"] = a1 # solver["L1"] = L1 solver["Fu"] = F_predict solver["Fu_corr"] = F_correct # solver["a3"] = a3 # solver["L3"] = L3 solver["bcs"] = bcs_NSu return solver
def les_setup(u_, mesh, Smagorinsky, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving Smagorinsky-Lilly LES model. """ DG = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) # Compute cell size and put in delta dim = mesh.geometry().dim() delta = Function(DG) delta.vector().zero() delta.vector().set_local( assemble(TestFunction(DG) * dx).array()**(1. / dim)) delta.vector().apply('insert') # Set up Smagorinsky form Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) nut_form = Smagorinsky['Cs']**2 * delta**2 * magS bcs_nut = derived_bcs(CG1, bcs['u0'], u_) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") return dict(Sij=Sij, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
def les_update(nut_, nut_form, A_mass, At, u_, dt, bc_ksgs, bt, ksgs_sol, KineticEnergySGS, CG1, ksgs, delta, **NS_namespace): p, q = TrialFunction(CG1), TestFunction(CG1) Ck = KineticEnergySGS["Ck"] Ce = KineticEnergySGS["Ce"] Sij = sym(grad(u_)) assemble(dt * inner(dot(u_, 0.5 * grad(p)), q) * dx + inner( (dt * Ce * sqrt(ksgs) / delta) * 0.5 * p, q) * dx + inner(dt * Ck * sqrt(ksgs) * delta * grad(0.5 * p), grad(q)) * dx, tensor=At) assemble(dt * 2 * Ck * delta * sqrt(ksgs) * inner(Sij, grad(u_)) * q * dx, tensor=bt) bt.axpy(1.0, A_mass * ksgs.vector()) bt.axpy(-1.0, At * ksgs.vector()) At.axpy(1.0, A_mass, True) # Solve for ksgs bc_ksgs.apply(At, bt) ksgs_sol.solve(At, ksgs.vector(), bt) ksgs.vector().set_local(ksgs.vector().array().clip(min=1e-7)) ksgs.vector().apply("insert") # Update nut_ nut_()
def les_update(nut_, nut_form, A_mass, At, u_, dt, bc_ksgs, bt, ksgs_sol, KineticEnergySGS, CG1, ksgs, delta, **NS_namespace): p, q = TrialFunction(CG1), TestFunction(CG1) Ck = KineticEnergySGS["Ck"] Ce = KineticEnergySGS["Ce"] Sij = sym(grad(u_)) assemble(dt*inner(dot(u_, 0.5*grad(p)), q)*dx + inner((dt*Ce*sqrt(ksgs)/delta)*0.5*p, q)*dx + inner(dt*Ck*sqrt(ksgs)*delta*grad(0.5*p), grad(q))*dx, tensor=At) assemble(dt*2*Ck*delta*sqrt(ksgs)*inner(Sij,grad(u_))*q*dx, tensor=bt) bt.axpy(1.0, A_mass*ksgs.vector()) bt.axpy(-1.0, At*ksgs.vector()) At.axpy(1.0, A_mass, True) # Solve for ksgs bc_ksgs.apply(At, bt) ksgs_sol.solve(At, ksgs.vector(), bt) ksgs.vector().set_local(ksgs.vector().array().clip(min=1e-7)) ksgs.vector().apply("insert") # Update nut_ nut_()
def les_setup(u_, mesh, Wale, bcs, CG1Function, nut_krylov_solver, **NS_namespace): """Set up for solving Wale LES model """ DG = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) delta = Function(DG) delta.vector().zero() delta.vector().axpy(1.0, assemble(TestFunction(DG)*dx)) Gij = grad(u_) Sij = sym(Gij) Skk = tr(Sij) dim = mesh.geometry().dim() Sd = sym(Gij*Gij) - 1./3.*Identity(mesh.geometry().dim())*Skk*Skk nut_form = Wale['Cw']**2 * pow(delta, 2./dim) * pow(inner(Sd, Sd), 1.5) / (Max(pow(inner(Sij, Sij), 2.5) + pow(inner(Sd, Sd), 1.25), 1e-6)) ff = FacetFunction("size_t", mesh, 0) bcs_nut = derived_bcs(CG1, bcs['u0'], u_) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, name='nut', bounded=True) return dict(Sij=Sij, Sd=Sd, Skk=Skk, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
def neumann_elasticity_data(): ''' Return: a bilinear form in the neumann elasticity problem L linear form in therein V function space, where a, L are defined bc homog. dirichlet conditions for case where we want pos. def problem z list of orthonormal vectors in the nullspace of A that form basis of ker(A) ''' mesh = UnitSquareMesh(40, 40) V = VectorFunctionSpace(mesh, 'CG', 1) u = TrialFunction(V) v = TestFunction(V) f = Expression(('sin(pi*x[0])', 'cos(pi*x[1])')) epsilon = lambda u: sym(grad(u)) # Material properties E, nu = 10.0, 0.3 mu, lmbda = Constant(E/(2*(1 + nu))), Constant(E*nu/((1 + nu)*(1 - 2*nu))) sigma = lambda u: 2*mu*epsilon(u) + lmbda*tr(epsilon(u))*Identity(2) a = inner(sigma(u), epsilon(v))*dx L = inner(f, v)*dx # Zero stress bc = DirichletBC(V, Constant((0, 0)), DomainBoundary()) z0 = interpolate(Constant((1, 0)), V).vector() normalize(z0, 'l2') z1 = interpolate(Constant((0, 1)), V).vector() normalize(z1, 'l2') X = mesh.coordinates().reshape((-1, 2)) c0, c1 = np.sum(X, axis=0)/len(X) z2 = interpolate(Expression(('x[1]-c1', '-(x[0]-c0)'), c0=c0, c1=c1), V).vector() normalize(z2, 'l2') z = [z0, z1, z2] # Check that this is orthonormal basis I = np.zeros((3, 3)) for i, zi in enumerate(z): for j, zj in enumerate(z): I[i, j] = zi.inner(zj) print I print la.norm(I-np.eye(3)) assert la.norm(I-np.eye(3)) < 1E-13 return a, L, V, bc, z
def les_setup(u_, mesh, Wale, bcs, CG1Function, nut_krylov_solver, **NS_namespace): """Set up for solving Wale LES model """ DG = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) # Compute cell size and put in delta delta = Function(DG) delta.vector().zero() delta.vector().axpy(1.0, assemble(TestFunction(DG)*dx)) # Set up Wale form Gij = grad(u_) Sij = sym(Gij) Skk = tr(Sij) dim = mesh.geometry().dim() Sd = sym(Gij*Gij) - 1./3.*Identity(mesh.geometry().dim())*Skk*Skk nut_form = Wale['Cw']**2 * pow(delta, 2./dim) * pow(inner(Sd, Sd), 1.5) / (Max(pow(inner(Sij, Sij), 2.5) + pow(inner(Sd, Sd), 1.25), 1e-6)) ff = FacetFunction("size_t", mesh, 0) bcs_nut = derived_bcs(CG1, bcs['u0'], u_) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, name='nut', bounded=True) return dict(Sij=Sij, Sd=Sd, Skk=Skk, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
def eps(self, u): e = df.sym(df.grad(u)) dim = self.mesh.geometric_dimension() if dim == 1: return df.as_vector([e[0, 0]]) if dim == 2: return df.as_vector([e[0, 0], e[1, 1], 2 * e[0, 1]]) if dim == 3: return df.as_vector([ e[0, 0], e[1, 1], e[2, 2], 2 * e[1, 2], 2 * e[0, 2], 2 * e[0, 1] ])
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 strain_rate_tensor(self, u): r"""Define the symmetric strain-rate tensor :param u: The velocity field (2D). :return: The strain rate tensor. """ r = dolfin.SpatialCoordinate(self._mesh)[0] ur = u[0] uz = u[1] ur_r = ur.dx(0) ur_z = ur.dx(1) uz_r = uz.dx(0) uz_z = uz.dx(1) return dolfin.sym( dolfin.as_tensor([[ur_r, 0, 0.5 * (uz_r + ur_z)], [0, ur / r, 0], [0.5 * (uz_r + ur_z), 0, uz_z]]))
def les_setup(u_, mesh, Smagorinsky, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving Smagorinsky-Lilly LES model. """ DG = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) dim = mesh.geometry().dim() delta = Function(DG) delta.vector().zero() delta.vector().axpy(1.0, assemble(TestFunction(DG)*dx)) delta.vector().apply('insert') Sij = sym(grad(u_)) magS = sqrt(2*inner(Sij,Sij)) nut_form = Smagorinsky['Cs']**2 * delta**2 * magS bcs_nut = derived_bcs(CG1, bcs['u0'], u_) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") return dict(Sij=Sij, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
def create_forms(W, rho, nu, F, g_a, p_h, boundary_markers): 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 n = df.FacetNormal(W.mesh()) ds = df.Measure("ds", subdomain_data=boundary_markers) L += df.inner(df.Constant((F, 0.0)), v_t) * ds(3) # driving force L -= p_h * df.inner(n, v_t) * (ds(2) + ds(4)) # hydrostatic balance return a, L
def les_setup(u_, mesh, Smagorinsky, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving Smagorinsky-Lilly LES model. """ DG = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) # Compute cell size and put in delta delta = Function(DG) delta.vector().zero() delta.vector().axpy(1.0, assemble(TestFunction(DG) * dx)) delta.vector().apply("insert") # Set up Smagorinsky form Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) nut_form = Smagorinsky["Cs"] ** 2 * delta ** 2 * magS bcs_nut = derived_bcs(CG1, bcs["u0"], u_) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") return dict(Sij=Sij, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
def stress_tensor(self, L, p): """ Return the Cauchy stress tensor for an incompressible Newtonian fluid, namely .. math:: \mathbf{T} = -p\mathbf{I} + 2\mu\\text{Sym}(\mathbf{L}), where :math:`\mathbf{L} = \\text{grad}(\mathbf{v})`, :math:`\mathbf{I}` is the identity tensor, :math:`p` is the hydrostatic pressure, and :math:`\mu` is the dynamic viscosity. Parameters ---------- L : ufl.differentiation.Grad The velocity gradient. p : dolfin.Function, ufl.indexed.Indexed The hydrostatic pressure. Returns ------- T : ufl.algebra.Sum The Cauchy stress tensor defined above. """ params = self._parameters dim = ufl.domain.find_geometric_dimension(L) mu = dlf.Constant(params['mu'], name='mu') I = dlf.Identity(dim) D = dlf.sym(L) return -p * I + dlf.Constant(2.0) * mu * D
def nn_setup(u_, mesh, ModifiedCross, CG1Function, nu_nn_krylov_solver, bcs, **NS_namespace): """ Set up for solving Modified-Cross non-Newtonian model. """ CG1 = FunctionSpace(mesh, "CG", 1) mu_inf = ModifiedCross['mu_inf'] mu_o = ModifiedCross['mu_o'] rho = ModifiedCross['rho'] lam = ModifiedCross['lam'] m_param = ModifiedCross['m_param'] a_param = ModifiedCross['a_param'] # Set up Modified Cross form Sij = sym(grad(u_)) SII = sqrt(2 * inner(Sij, Sij)) nu_nn_form = ((mu_o - mu_inf) / ((1 + (lam * SII)**m_param)**a_param)) / rho #bcs_nu_nn = derived_bcs(CG1, bcs['u0'], u_) nunn_ = CG1Function(nu_nn_form, mesh, method=nu_nn_krylov_solver, bounded=True, name="nu_nn") return dict(Sij=Sij, nunn_=nunn_, bcs_nu_nn=[])
def initialize_with_field(self, u): super().initialize_with_field(u) I = Identity(len(u)) eps = sym(grad(u)) for m in self.material_parameters: E = m.get('E', None) nu = m.get('nu', None) mu = m.get('mu', None) lm = m.get('lm', None) if mu is None: if E is None or nu is None: raise RuntimeError( 'Material model requires parameter "mu"; ' 'otherwise, require parameters "E" and "nu".') mu = E / (2 * (1 + nu)) if lm is None: if E is None or nu is None: raise RuntimeError( 'Material model requires parameter "lm"; ' 'otherwise, require parameters "E" and "nu".') lm = E * nu / ((1 + nu) * (1 - 2 * nu)) sig = 2 * mu * eps + lm * tr(eps) * I psi = 0.5 * inner(sig, eps) self.psi.append(psi) self.pk1.append(sig) self.pk2.append(sig)
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
def test_unsteady_stokes(): nx, ny = 15, 15 k = 1 nu = Constant(1.0e-0) dt = Constant(2.5e-2) num_steps = 20 theta0 = 1.0 # Initial theta value theta1 = 0.5 # Theta after 1 step theta = Constant(theta0) mesh = UnitSquareMesh(nx, ny) # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells u_exact = Expression( ( "sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])", t=0, degree=7, domain=mesh) du_exact = Expression( ( "cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) ux_exact = Expression( ( "x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), degree=7, domain=mesh, ) px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh) sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh) f = du_exact + sin_ext * div(px_exact * Identity(2) - 2 * sym(grad(ux_exact))) Vhigh = VectorFunctionSpace(mesh, "DG", 7) Phigh = FunctionSpace(mesh, "DG", 7) # New syntax: V = VectorElement("DG", mesh.ufl_cell(), k) Q = FiniteElement("DG", mesh.ufl_cell(), k - 1) Vbar = VectorElement("DGT", mesh.ufl_cell(), k) Qbar = FiniteElement("DGT", mesh.ufl_cell(), k) mixedL = FunctionSpace(mesh, MixedElement([V, Q])) mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar])) V2 = FunctionSpace(mesh, V) Uh = Function(mixedL) Uhbar = Function(mixedG) U0 = Function(mixedL) Uhbar0 = Function(mixedG) u0, p0 = split(U0) ubar0, pbar0 = split(Uhbar0) ustar = Function(V2) # Then the boundary conditions bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma) bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise") bcs = [bc0, bc1] alpha = Constant(6 * k * k) forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha).forms_unsteady(ustar, dt, nu, f) ssc = StokesStaticCondensation( mesh, forms_stokes["A_S"], forms_stokes["G_S"], forms_stokes["G_ST"], forms_stokes["B_S"], forms_stokes["Q_S"], forms_stokes["S_S"], ) t = 0.0 step = 0 for step in range(num_steps): step += 1 t += float(dt) if comm.Get_rank() == 0: print("Step " + str(step) + " Time " + str(t)) # Set time level in exact solution u_exact.t = t p_exact.t = t du_exact.t = t - (1 - float(theta)) * float(dt) sin_ext.t = t - (1 - float(theta)) * float(dt) ssc.assemble_global_lhs() ssc.assemble_global_rhs() for bc in bcs: ssc.apply_boundary(bc) ssc.solve_problem(Uhbar, Uh, "none", "default") assign(U0, Uh) assign(ustar, U0.sub(0)) assign(Uhbar0, Uhbar) if step == 1: theta.assign(theta1) udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx)) u_ex_h = interpolate(u_exact, Vhigh) p_ex_h = interpolate(p_exact, Phigh) u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h) * dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h) * dx)) assert udiv_e < 1e-12 assert u_error < 1.5e-4 assert p_error < 1e-2
def strain(u): return dolfin.sym(dolfin.grad(u))
def strain(self, u): """ Strain tensor: s = .5( u_{i,j} + u_{j,i}) """ return dl.sym(dl.grad(u))
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 epsilon(u): return df.sym(df.nabla_grad(u))
def test_steady_stokes(k): # Polynomial order and mesh resolution nx_list = [4, 8, 16] nu = Constant(1) if comm.Get_rank() == 0: print('{:=^72}'.format('Computing for polynomial order ' + str(k))) # Error listst error_u, error_p, error_div = [], [], [] for nx in nx_list: if comm.Get_rank() == 0: print('# Resolution ' + str(nx)) mesh = UnitSquareMesh(nx, nx) # Get forcing from exact solutions u_exact, p_exact = exact_solution(mesh) f = div(p_exact * Identity(2) - 2 * nu * sym(grad(u_exact))) # Define FunctionSpaces and functions V = VectorElement("DG", mesh.ufl_cell(), k) Q = FiniteElement("DG", mesh.ufl_cell(), k - 1) Vbar = VectorElement("DGT", mesh.ufl_cell(), k) Qbar = FiniteElement("DGT", mesh.ufl_cell(), k) mixedL = FunctionSpace(mesh, MixedElement([V, Q])) mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar])) Uh = Function(mixedL) Uhbar = Function(mixedG) # Set forms alpha = Constant(6 * k * k) forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha).forms_steady(nu, f) # No-slip boundary conditions, set pressure in one of the corners bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma) bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise") bcs = [bc0, bc1] # Initialize static condensation class ssc = StokesStaticCondensation(mesh, forms_stokes['A_S'], forms_stokes['G_S'], forms_stokes['B_S'], forms_stokes['Q_S'], forms_stokes['S_S'], bcs) # Assemble global system and incorporates bcs ssc.assemble_global_system(True) # Solve using mumps ssc.solve_problem(Uhbar, Uh, "mumps", "default") # Compute velocity/pressure/local div error uh, ph = Uh.split() e_u = np.sqrt(np.abs(assemble(dot(uh - u_exact, uh - u_exact) * dx))) e_p = np.sqrt(np.abs(assemble((ph - p_exact) * (ph - p_exact) * dx))) e_d = np.sqrt(np.abs(assemble(div(uh) * div(uh) * dx))) if comm.rank == 0: error_u.append(e_u) error_p.append(e_p) error_div.append(e_d) print('Error in velocity ' + str(error_u[-1])) print('Error in pressure ' + str(error_p[-1])) print('Local mass error ' + str(error_div[-1])) if comm.rank == 0: iterator_list = [1. / float(nx) for nx in nx_list] conv_u = compute_convergence(iterator_list, error_u) conv_p = compute_convergence(iterator_list, error_p) assert any(conv > k + 0.75 for conv in conv_u) assert any(conv > (k - 1) + 0.75 for conv in conv_p)
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 setup_NS(w_NS, u, p, v, q, p0, q0, dx, ds, normal, dirichlet_bcs, neumann_bcs, boundary_to_mark, u_1, phi_, rho_, rho_1, g_, M_, mu_, rho_e_, c_, V_, c_1, V_1, dbeta, solutes, per_tau, drho, sigma_bar, eps, dveps, grav, fric, u_comoving, enable_PF, enable_EC, use_iterative_solvers, use_pressure_stabilization, p_lagrange, q_rhs): """ Set up the Navier-Stokes subproblem. """ # F = ( # per_tau * rho_ * df.dot(u - u_1, v)*dx # + rho_*df.inner(df.grad(u), df.outer(u_1, v))*dx # + 2*mu_*df.inner(df.sym(df.grad(u)), df.grad(v))*dx # - p * df.div(v)*dx # + df.div(u)*q*dx # - df.dot(rho_*grav, v)*dx # ) mom_1 = rho_1 * (u_1 + u_comoving) if enable_PF: mom_1 += -M_ * drho * df.nabla_grad(g_) F = (per_tau * rho_1 * df.dot(u - u_1, v) * dx + fric * mu_ * df.dot(u + u_comoving, v) * dx + 2 * mu_ * df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx - p * df.div(v) * dx + q * df.div(u) * dx + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 0.5 * (per_tau * (rho_ - rho_1) * df.dot(u, v) - df.dot(mom_1, df.nabla_grad(df.dot(u, v)))) * dx - rho_ * df.dot(grav, v) * dx - mu_ * df.dot(df.nabla_grad(u) * normal, v) * df.ds) for boundary_name, slip_length in neumann_bcs["u"].items(): F += 1./slip_length * \ df.dot(u, v) * ds(boundary_to_mark[boundary_name]) for boundary_name, pressure in neumann_bcs["p"].items(): F += pressure * df.dot(normal, v) * ds(boundary_to_mark[boundary_name]) # - 2*mu_*df.dot(df.dot(df.sym(df.nabla_grad(u)), v), # normal)) * ds(boundary_to_mark[boundary_name]) if enable_PF: F += phi_ * df.dot(df.nabla_grad(g_), v) * dx if enable_EC: for ci_, ci_1, dbetai, solute in zip(c_, c_1, dbeta, solutes): zi = solute[1] F += df.dot(df.grad(ci_), v)*dx \ + zi*ci_1*df.dot(df.grad(V_), v)*dx if enable_PF: F += ci_ * dbetai * df.dot(df.grad(phi_), v) * dx 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) problem = df.LinearVariationalProblem(a, L, w_NS, dirichlet_bcs) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers and use_pressure_stabilization: solver.parameters["linear_solver"] = "gmres" #solver.parameters["preconditioner"] = "jacobi" #solver.parameters["preconditioner"] = "ilu" return solver
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 strain_displacement(u): return dolfin.sym(dolfin.grad(u))
def get_residual_form(u, v, rho_e, V_density, tractionBC, T, iteration_number, additive='strain', k=8., method='RAMP'): df.dx = df.dx(metadata={"quadrature_degree": 4}) # stiffness = rho_e/(1 + 8. * (1. - rho_e)) if method == 'SIMP': stiffness = rho_e**3 else: stiffness = rho_e / (1 + 8. * (1. - rho_e)) # print('the value of stiffness is:', rho_e.vector().get_local()) # Kinematics d = len(u) I = df.Identity(d) # Identity tensor F = I + df.grad(u) # Deformation gradient C = F.T * F # Right Cauchy-Green tensor # Invariants of deformation tensors Ic = df.tr(C) J = df.det(F) stiffen_pow = 1. threshold_vol = 1. eps_star = 0.05 # print("eps_star--------") if additive == 'strain': print("additive == strain") if iteration_number == 1: print('iteration_number == 1') eps = df.sym(df.grad(u)) eps_dev = eps - 1 / 3 * df.tr(eps) * df.Identity(2) eps_eq = df.sqrt(2.0 / 3.0 * df.inner(eps_dev, eps_dev)) # eps_eq_proj = df.project(eps_eq, density_function_space) ratio = eps_eq / eps_star ratio_proj = df.project(ratio, V_density) c1_e = k * (5.e-2) / (1 + 8. * (1. - (5.e-2))) / 6 c2_e = df.Function(V_density) c2_e.vector().set_local(5e-4 * np.ones(V_density.dim())) fFile = df.HDF5File(df.MPI.comm_world, "c2_e_proj.h5", "w") fFile.write(c2_e, "/f") fFile.close() fFile = df.HDF5File(df.MPI.comm_world, "ratio_proj.h5", "w") fFile.write(ratio_proj, "/f") fFile.close() iteration_number += 1 E = k * stiffness phi_add = (1 - stiffness) * ((c1_e * (Ic - 3)) + (c2_e * (Ic - 3))**2) else: ratio_proj = df.Function(V_density) fFile = df.HDF5File(df.MPI.comm_world, "ratio_proj.h5", "r") fFile.read(ratio_proj, "/f") fFile.close() c2_e = df.Function(V_density) fFile = df.HDF5File(df.MPI.comm_world, "c2_e_proj.h5", "r") fFile.read(c2_e, "/f") fFile.close() c1_e = k * (5.e-2) / (1 + 8. * (1. - (5.e-2))) / 6 c2_e = df.conditional(df.le(ratio_proj, eps_star), c2_e * df.sqrt(ratio_proj), c2_e * (ratio_proj**3)) phi_add = (1 - stiffness) * ((c1_e * (Ic - 3)) + (c2_e * (Ic - 3))**2) E = k * stiffness c2_e_proj = df.project(c2_e, V_density) print('c2_e projected -------------') eps = df.sym(df.grad(u)) eps_dev = eps - 1 / 3 * df.tr(eps) * df.Identity(2) eps_eq = df.sqrt(2.0 / 3.0 * df.inner(eps_dev, eps_dev)) # eps_eq_proj = df.project(eps_eq, V_density) ratio = eps_eq / eps_star ratio_proj = df.project(ratio, V_density) fFile = df.HDF5File(df.MPI.comm_world, "c2_e_proj.h5", "w") fFile.write(c2_e_proj, "/f") fFile.close() fFile = df.HDF5File(df.MPI.comm_world, "ratio_proj.h5", "w") fFile.write(ratio_proj, "/f") fFile.close() elif additive == 'vol': print("additive == vol") stiffness = stiffness / (df.det(F)**stiffen_pow) # stiffness = df.conditional(df.le(df.det(F),threshold_vol), (stiffness/(df.det(F)/threshold_vol))**stiffen_pow, stiffness) E = k * stiffness elif additive == 'False': print("additive == False") E = k * stiffness # rho_e is the design variable, its values is from 0 to 1 nu = 0.4 # Poisson's ratio lambda_ = E * nu / (1. + nu) / (1 - 2 * nu) mu = E / 2 / (1 + nu) #lame's parameters # Stored strain energy density (compressible neo-Hookean model) psi = (mu / 2) * (Ic - 3) - mu * df.ln(J) + (lambda_ / 2) * (df.ln(J))**2 # print('the length of psi is:',len(psi.vector())) if additive == 'strain': psi += phi_add B = df.Constant((0.0, 0.0)) # Total potential energy '''The first term in this equation provided this error''' Pi = psi * df.dx - df.dot(B, u) * df.dx - df.dot(T, u) * tractionBC res = df.derivative(Pi, u, v) return res
def differential_op(self, u): return sym(nabla_grad(u))
## Next make a function space V = d.VectorFunctionSpace(mesh, 'Lagrange', 1) # Create a test function and a trial function, and a source term: u = d.TrialFunction(V) w = d.TestFunction(V) b = d.Constant((1.0,0.,0.)) # Elasticity parameters: E, nu = 10., 0.3 mu, lambda_param = E / (2. * (1.+nu)), E * nu / ((1. + nu) * (1.-2. * nu)) # Stress tensor: # + usually of form \sigma_{ij} = \lambda e_{kk}\delta_{ij} + 2\mu e_{ij}, # + or = \lambda Tr(e_{ij})I + 2\mu e_{ij}, for e_{ij} the strain tensor. sigma = lambda_param*d.tr(d.grad(u)) * d.Identity(w.cell().d) + 2 * mu * d.sym(d.grad(u)) # Governing balance equation: F = d.inner(sigma, d.grad(w)) * d.dx - d.dot(b,w)*d.dx # Extract the bi- and linear forms from F: a = d.lhs(F) L = d.rhs(F) # Dirichlet BC on entire boundary: c = d.Constant((0.,0.,0.)) bc = d.DirichletBC(V, c, d.DomainBoundary()) ## Testing some new boundary definitions: def bzo_boundary(r_vec, on_boundary):
def setup_NSu(w_NSu, u, v, dx, ds, normal, dirichlet_bcs_NSu, neumann_bcs, boundary_to_mark, u_, u_1, p_, p_1, phi_, phi_1, rho_, rho_1, g_, g_1, c_, c_1, M_, M_1, mu_, mu_1, rho_e_, rho_e_1, V_, dt, drho, sigma_bar, eps, dveps, grav, dbeta, z, enable_PF, enable_EC, use_iterative_solvers, **namespace): """ Set up the Navier-Stokes velocity subproblem. """ mom_1 = rho_1 * u_1 if enable_PF: mom_1 += -drho * M_1 * df.grad(g_1) 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 - p_1 * df.div(v) * dx - rho_ * df.dot(grav, v) * dx + 0.5 * (1. / dt * (rho_ - rho_1) - df.inner(mom_1, df.grad(df.dot(u, v)))) * dx) if enable_PF: F_predict += phi_1 * df.dot(df.grad(g_), v) * dx for boundary_name, pressure in neumann_bcs["p"].items(): F_predict += pressure * df.inner(normal, v) * ds( boundary_to_mark[boundary_name]) if enable_EC: for ci_, ci_1_ in zip(c_, c_1): # F_predict += df.dot(df.nabla_grad(ci_), v) * dx pass #if enable_EC and rho_e_ != 0: # F += rho_e_1 * df.dot(df.nabla_grad(V_), v) * dx #if enable_PF and enable_EC: # # Not clear how to discretize this term! # # F += dveps * df.dot(df.grad(phi_), v)*df.dot(df.grad(V_), # # df.grad(V_))*dx # F_c = [] # for ci_, ci_1, zi, dbetai in zip(c_, c_1, z, dbeta): # F_ci = ci_1*dbetai*df.dot(df.grad(phi_), v)*dx # F_c.append(F_ci) # F += sum(F_c) solvers = dict() a_predict, L_predict = df.lhs(F_predict), df.rhs(F_predict) 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"] = "jacobi" # "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"] = "cg" # "bicgstab" solvers["correct"].parameters["preconditioner"] = "jacobi" # "amg" return solvers
def strain(v): return dl.sym(dl.nabla_grad(v))
def epsilon(u): # Define symmetric gradient return sym(nabla_grad(u))
def setup_NSPFEC(w_NSPFEC, w_1NSPFEC, dirichlet_bcs_NSPFEC, neumann_bcs, boundary_to_mark, dx, ds, normal, v, q, q0, psi, h, b, U, u_, p_, p0_, phi_, g_, c_, V_, u_1, p_1, p0_1, phi_1, g_1, c_1, V_1, M_, nu_, veps_, rho_, K_, beta_, rho_e_, dbeta, dveps, drho, per_tau, sigma_bar, eps, grav, z, solutes, enable_NS, enable_PF, enable_EC, use_iterative_solvers, p_lagrange, q_rhs): """ The full problem of electrohydrodynamics in two phases. Note that it is possible to turn off the different parts at will. """ # Setup of the Navier-Stokes part of F mom_ = rho_*u_ if enable_PF: mom_ += -M_*drho * df.nabla_grad(g_) F = [] if enable_NS: F_NS = (per_tau * rho_ * df.dot(u_ - u_1, v) * dx + df.inner(df.nabla_grad(u_), df.outer(mom_, v)) * dx + 2*nu_*df.inner(df.sym(df.nabla_grad(u_)), df.sym(df.nabla_grad(v))) * dx - p_ * df.div(v) * dx - df.div(u_) * q * dx - df.dot(rho_ * grav, v) * dx) # if enable_PF: # F_NS += - sigma_bar*eps*df.inner( # df.outer(df.grad(phi_), # df.grad(phi_)), df.grad(v)) * dx # if enable_EC and rho_e_ != 0: # F_NS += rho_e_*df.dot(df.grad(V_), v) * dx # if enable_PF and enable_EC: # F_NS += dveps*df.dot( # df.grad(phi_), v)*df.dot(df.grad(V_), # df.grad(V_)) * dx if enable_PF: F_NS += phi_*df.dot(df.grad(g_), v) * dx if enable_EC: for ci_, dbetai, solute in zip(c_, dbeta, solutes): zi = solute[1] F_NS += df.dot(df.grad(ci_), v) * dx \ + ci_*dbetai*df.dot(df.grad(phi_), v) * dx \ + zi*ci_*df.dot(df.grad(V_), v) * dx # Slip boundary condition for boundary_name, slip_length in neumann_bcs["u"].items(): F_NS += 1./slip_length * \ df.dot(u_, v) * ds(boundary_to_mark[boundary_name]) # Pressure boundary condition for boundary_name, pressure in neumann_bcs["p"].items(): F_NS += pressure * df.inner( normal, v) * ds(boundary_to_mark[boundary_name]) # Lagrange pressure if p_lagrange: F_NS += (p_*q0 + q*p0_)*dx # RHS source terms if "u" in q_rhs: F_NS += -df.dot(q_rhs["u"], v)*dx F.append(F_NS) # Setup of the phase-field equations if enable_PF: phi_1_flt = unit_interval_filter(phi_1) F_PF_phi = (per_tau*(phi_-phi_1_flt)*psi*df.dx + M_*df.dot(df.grad(g_), df.grad(psi)) * dx) if enable_NS: F_PF_phi += df.dot(u_, df.grad(phi_)) * psi * dx F_PF_g = (g_ * h * dx - sigma_bar*eps*df.dot(df.grad(phi_), df.grad(h)) * dx - sigma_bar/eps*diff_pf_potential(phi_) * h * dx) if enable_EC: F_PF_g += (-sum([dbeta_i * ci_ * h * dx for dbeta_i, ci_ in zip(dbeta, c_)]) + dveps * df.dot(df.grad(V_), df.grad(V_)) * h * dx) # Contact angle boundary condtions for boundary_name, costheta in neumann_bcs["phi"].items(): fw_prime = diff_pf_contact(phi_) F_PF_g += sigma_bar * costheta * fw_prime * h * ds( boundary_to_mark[boundary_name]) # RHS source terms if "phi" in q_rhs: F_PF_phi += -q_rhs["phi"]*psi*dx F_PF = F_PF_phi + F_PF_g F.append(F_PF) # Setup of the electrochemistry if enable_EC: F_E_c = [] for ci_, ci_1, bi, Ki_, zi, dbetai, solute in zip( c_, c_1, b, K_, z, dbeta, solutes): ci_1_flt = max_value(ci_1, 0.) F_E_ci = (per_tau*(ci_-ci_1_flt)*bi*df.dx + Ki_*df.dot(df.grad(ci_), df.grad(bi))*df.dx) if zi != 0: F_E_ci += Ki_*zi*ci_*df.dot(df.grad(V_), df.grad(bi))*df.dx if enable_NS: F_E_ci += df.dot(u_, df.grad(ci_))*bi*df.dx if enable_PF: F_E_ci += Ki_*ci_*dbetai*df.dot(df.grad(phi_), df.grad(bi)) * dx if solute[0] in q_rhs: F_E_ci += - q_rhs[solute[0]] * bi * dx F_E_c.append(F_E_ci) F_E_V = veps_*df.dot(df.grad(V_), df.grad(U))*df.dx if rho_e_ != 0: F_E_V += -rho_e_*U*df.dx # Surface charge boundary condition for boundary_name, sigma_e in neumann_bcs["V"].items(): F_E_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) # RHS source terms if "V" in q_rhs: F_E_V += q_rhs["V"]*U*dx F_E = sum(F_E_c) + F_E_V F.append(F_E) F = sum(F) J = df.derivative(F, w_NSPFEC) problem_NSPFEC = df.NonlinearVariationalProblem(F, w_NSPFEC, dirichlet_bcs_NSPFEC, J) solver_NSPFEC = df.NonlinearVariationalSolver(problem_NSPFEC) if use_iterative_solvers: solver_NSPFEC.parameters['newton_solver']['linear_solver'] = 'gmres' solver_NSPFEC.parameters['newton_solver']['preconditioner'] = 'ilu' return solver_NSPFEC
def epsilon(self, uu): return dolfin.sym(dolfin.grad(uu))
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = FacetFunction("size_t", mesh, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
def epsilon(u): # Define symmetric gradient return dolfin.sym(dolfin.nabla_grad(u))
def __ufl_forms(self, nu, f): (w, q, wbar, qbar) = self.__test_functions() (u, p, ubar, pbar) = self.__trial_functions() # Infer geometric dimension zero_vec = np.zeros(self.gdim) ds = self.ds n = self.n he = self.he alpha = self.alpha h_d = self.h_d beta_stab = self.beta_stab facet_integral = self.facet_integral pI = p * Identity( self.mixedL.sub(1).ufl_cell().topological_dimension()) pbI = pbar * \ Identity(self.mixedL.sub(1).ufl_cell().topological_dimension()) # Upper left block # Contribution comes from local momentum balance AB = inner(2*nu*sym(grad(u)), grad(w))*dx \ + facet_integral(dot(-2*nu*sym(grad(u))*n + (2*nu*alpha/he)*u, w)) \ + facet_integral(dot(-2*nu*u, sym(grad(w))*n)) \ - inner(pI, grad(w))*dx # Contribution comes from local mass balance BtF = -dot(q, div(u))*dx - \ facet_integral(beta_stab*he/(nu+1)*dot(p, q)) A_S = AB + BtF # Upper right block # Contribution from local momentum CD = facet_integral(-alpha/he*2*nu*inner(ubar, w)) \ + facet_integral(2*nu*inner(ubar, sym(grad(w))*n)) \ + facet_integral(dot(pbI*n, w)) H = facet_integral(beta_stab * he / (nu + 1) * dot(pbar, q)) G_S = CD + H # Transpose block CDT = facet_integral(- alpha/he*2*nu*inner(wbar, u)) \ + facet_integral(2*nu*inner(wbar, sym(grad(u))*n)) \ + facet_integral(qbar * dot(u, n)) HT = facet_integral(beta_stab * he / (nu + 1) * dot(p, qbar)) G_ST = CDT + HT # Lower right block, penalty on ds(98) approximates free-slip KL = facet_integral(alpha/he * 2 * nu*dot(ubar, wbar)) \ - facet_integral(dot(pbar*n, wbar)) \ + Constant(1E12)/he * inner(outer(ubar, wbar), outer(n, n)) * ds(98) LtP = - facet_integral(dot(ubar, n)*qbar) \ - facet_integral(beta_stab*he/(nu+1) * pbar * qbar) B_S = KL + LtP # Righthandside Q_S = dot(f, w) * dx S_S = facet_integral(dot(Constant(zero_vec), wbar)) S_S += dot(h_d[0], wbar) * ds(99) + dot(h_d[1], wbar) * ds( 100) #Neumann BC return { 'A_S': A_S, 'G_S': G_S, 'G_ST': G_ST, 'B_S': B_S, 'Q_S': Q_S, 'S_S': S_S }