def solve_initial_pressure(w_NSp, p, q, u, v, bcs_NSp, M_, g_, phi_, rho_, rho_e_, V_, drho, sigma_bar, eps, grav, dveps, enable_PF, enable_EC): V = u.function_space() grad_p = df.TrialFunction(V) grad_p_out = df.Function(V) F_grad_p = (df.dot(grad_p, v) * df.dx - rho_ * df.dot(grav, v) * df.dx) if enable_PF: F_grad_p += -drho * M_ * df.inner(df.grad(u), df.outer(df.grad(g_), v)) * df.dx F_grad_p += -sigma_bar * eps * df.inner( df.outer(df.grad(phi_), df.grad(phi_)), df.grad(v)) * df.dx if enable_EC and rho_e_ != 0: F_grad_p += rho_e_ * df.dot(df.grad(V_), v) * df.dx if enable_PF and enable_EC: F_grad_p += dveps * df.dot(df.grad(phi_), v) * df.dot( df.grad(V_), df.grad(V_)) * df.dx info_red("Solving initial grad_p...") df.solve(df.lhs(F_grad_p) == df.rhs(F_grad_p), grad_p_out) F_p = (df.dot(df.grad(q), df.grad(p)) * df.dx - df.dot(df.grad(q), grad_p_out) * df.dx) info_red("Solving initial p...") df.solve(df.lhs(F_p) == df.rhs(F_p), w_NSp, bcs_NSp)
def wedge(a, b): ''' Calculates the wedge product of vectors a and b .. math:: a \wedge b : = a \otimes b - b\otimes a ''' return outer(a, b) - outer(b, a)
def forms_theta_nlinear_np(self, v0, v_int, Ubar0, dt, theta_map=Constant(1.0), theta_L=Constant(1.0), duh0=Constant((0., 0.)), duh00=Constant((0., 0)), h=Constant((0., 0.)), neumann_idx=99): ''' No particles in mass matrix ''' # Define trial test functions (v, lamb, vbar) = self.__trial_functions() (w, tau, wbar) = self.__test_functions() (zero_vec, h, duh0, duh00) = self.__check_geometric_dimension(h, duh0, duh00) beta_map = self.beta_map n = self.n facet_integral = self.facet_integral # Define v_star v_star = v0 + (1-theta_L) * duh00 + theta_L * duh0 Udiv = v0 + duh0 outer_v_a = outer(w, Udiv) outer_v_a_o = outer(v_star, Udiv) outer_ubar_a = outer(vbar, Ubar0) # Switch to detect in/outflow boundary gamma = conditional(ge(dot(Udiv, n), 0), 0, 1) # LHS contribution s N_a = dot(v, w) * dx + facet_integral(beta_map*dot(v, w)) G_a = dot(lamb, w)/dt * dx - theta_map*inner(outer_v_a, grad(lamb))*dx \ + theta_map * (1-gamma) * dot(outer_v_a * n, lamb) * self.ds(neumann_idx) L_a = -facet_integral(beta_map * dot(vbar, w)) H_a = facet_integral(dot(outer_ubar_a*n, tau)) \ - dot(outer_ubar_a*n, tau) * self.ds(neumann_idx) B_a = facet_integral(beta_map * dot(vbar, wbar)) # RHS contributions Q_a = dot(v_int, w) * dx R_a = dot(v_star, tau)/dt * dx \ + (1-theta_map)*inner(outer_v_a_o, grad(tau))*dx \ - gamma * dot(h, tau) * self.ds(neumann_idx) S_a = facet_integral(dot(Constant(zero_vec), wbar)) return self.__fem_forms(N_a, G_a, L_a, H_a, B_a, Q_a, R_a, S_a)
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 blocks(self): aa, ff = super(FormulationMinimallyConstrained, self).blocks() n = df.FacetNormal(self.mesh) ds = df.Measure('ds', self.mesh) u, P = self.uu_[0], self.uu_[2] v, Q = self.vv_[0], self.vv_[2] aa[0].append(- df.inner(P, df.outer(v, n))*ds) aa[1].append(0) aa.append([- df.inner(Q, df.outer(u, n))*ds, 0, 0]) ff.append(0) return [aa, ff]
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 SecondPiolaStress(self, F, p=None, deviatoric=False): import dolfin from pulse import kinematics material = self.material I = kinematics.SecondOrderIdentity(F) f0 = material.f0 f0f0 = dolfin.outer(f0, f0) I1 = dolfin.variable(material.active.I1(F)) I4f = dolfin.variable(material.active.I4(F)) Fe = material.active.Fe(F) Fa = material.active.Fa Ce = Fe.T * Fe # fe = Fe*f0 # fefe = dolfin.outer(fe, fe) # Elastic volume ratio J = dolfin.variable(dolfin.det(Fe)) # Active volume ration Ja = dolfin.det(Fa) dim = self.geometry.dim() Ce_bar = pow(J, -2.0 / float(dim)) * Ce w1 = material.W_1(I1, diff=1, dim=dim) w4f = material.W_4(I4f, diff=1) # Total Stress S_bar = Ja * (2 * w1 * I + 2 * w4f * f0f0) * dolfin.inv(Fa).T if material.is_isochoric: # Deviatoric Dev_S_bar = S_bar - (1.0 / 3.0) * dolfin.inner( S_bar, Ce_bar) * dolfin.inv(Ce_bar) S_mat = J**(-2.0 / 3.0) * Dev_S_bar else: S_mat = S_bar # Volumetric if p is None or deviatoric: S_vol = dolfin.zero((dim, dim)) else: psi_vol = material.compressibility(p, J) S_vol = J * dolfin.diff(psi_vol, J) * dolfin.inv(Ce) # Active stress wactive = material.active.Wactive(F, diff=1) eta = material.active.eta S_active = wactive * (f0f0 + eta * (I - f0f0)) S = S_mat + S_vol + S_active return S
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 forms_theta_nlinear_multiphase(self, rho, rho0, rho00, rhobar, v0, Ubar0, dt, theta_map, theta_L=Constant(1.0), duh0=Constant((0., 0.)), duh00=Constant((0., 0)), h=Constant((0., 0.)), neumann_idx=99): (v, lamb, vbar) = self.__trial_functions() (w, tau, wbar) = self.__test_functions() (zero_vec, h, duh0, duh00) = self.__check_geometric_dimension(h, duh0, duh00) beta_map = self.beta_map n = self.n facet_integral = self.facet_integral # FIXME: To be deprecated rhov_star = rho0*(v0 + theta_L * duh0) + rho00 * (1-theta_L) * duh00 Udiv = v0 + duh0 outer_v_a = outer(rho * w, Udiv) outer_v_a_o = outer(rho0 * Udiv, Udiv) outer_ubar_a = outer(rhobar * vbar, Ubar0) # Switch to detect in/outflow boundary gamma = conditional(ge(dot(Udiv, n), 0), 0, 1) # LHS contribution N_a = facet_integral(beta_map*dot(v, w)) G_a = dot(lamb, rho * w)/dt * dx - theta_map*inner(outer_v_a, grad(lamb))*dx \ + theta_map * (1-gamma) * dot(outer_v_a * n, lamb) * self.ds(neumann_idx) L_a = -facet_integral(beta_map * dot(vbar, w)) H_a = facet_integral(dot(outer_ubar_a*n, tau)) \ - dot(outer_ubar_a*n, tau) * self.ds(neumann_idx) B_a = facet_integral(beta_map * dot(vbar, wbar)) # RHS contribution Q_a = dot(zero_vec, w) * dx R_a = dot(rhov_star, tau)/dt*dx \ + (1-theta_map)*inner(outer_v_a_o, grad(tau))*dx \ + gamma * dot(h, tau) * self.ds(neumann_idx) S_a = facet_integral(dot(zero_vec, wbar)) return self.__fem_forms(N_a, G_a, L_a, H_a, B_a, Q_a, R_a, S_a)
def Fa(self): f0 = self.f0 d = get_dimesion(f0) f0f0 = dolfin.outer(f0, f0) I = kinematics.SecondOrderIdentity(f0f0) mgamma = self._mgamma Fa = mgamma * f0f0 + pow(mgamma, -1.0 / float(d - 1)) * (I - f0f0) return Fa
def solve(self): """ Solves the stokes equation with the current multimesh """ (u, p) = TrialFunctions(self.VQ) (v, q) = TestFunctions(self.VQ) n = FacetNormal(self.multimesh) h = 2.0 * Circumradius(self.multimesh) alpha = Constant(6.0) tensor_jump = lambda u: outer(u("+"), n("+")) + outer(u("-"), n("-")) a_s = inner(grad(u), grad(v)) * dX a_IP = - inner(avg(grad(u)), tensor_jump(v))*dI\ - inner(avg(grad(v)), tensor_jump(u))*dI\ + alpha/avg(h) * inner(jump(u), jump(v))*dI a_O = inner(jump(grad(u)), jump(grad(v))) * dO b_s = -div(u) * q * dX - div(v) * p * dX b_IP = jump(u, n) * avg(q) * dI + jump(v, n) * avg(p) * dI l_s = inner(self.f, v) * dX s_C = h*h*inner(-div(grad(u)) + grad(p), -div(grad(v)) - grad(q))*dC\ + h("+")*h("+")*inner(-div(grad(u("+"))) + grad(p("+")), -div(grad(v("+"))) + grad(q("+")))*dO l_C = h*h*inner(self.f, -div(grad(v)) - grad(q))*dC\ + h("+")*h("+")*inner(self.f("+"), -div(grad(v("+"))) - grad(q("+")))*dO a = a_s + a_IP + a_O + b_s + b_IP + s_C l = l_s + l_C A = assemble_multimesh(a) L = assemble_multimesh(l) [bc.apply(A, L) for bc in self.bcs] self.VQ.lock_inactive_dofs(A, L) solve(A, self.w.vector(), L, "mumps") self.splitMMF()
def Fa(self): if self.model == ActiveModels.active_stress: return dolfin.Identity(self.dim) f0 = self.f0 f0f0 = dolfin.outer(f0, f0) Id = dolfin.Identity(self.dim) mgamma = 1 - self.activation_field Fa = mgamma * f0f0 + pow(mgamma, -1.0 / float(self.dim - 1)) * (Id - f0f0) return Fa
def projectAGG(self, a=Constant(0.0), g=Constant(0.0), gamma=Constant([0, 0, 1])): """ Calculate and project growth function from given :math:`a`, :math:`g` and :math:`\gamma` values """ self.a.project(a) self.g.project(g) self.gamma.project(gamma / sqrt(inner(gamma, gamma))) g0 = g * (1 - a) g1 = g * (1 + 2 * a) self.project(Identity(3) * g0 + (g1 - g0) * outer(gamma, gamma))
def set_model(self): measures = [self.dx, self.ds, self.dS] # import pdb; pdb.set_trace() if self.parameters['material']['p'] == 'zero': from plate_lib import ActuationOverNematicFoundation actuation = ActuationOverNematicFoundation(self.z, self.mesh, self.parameters, measures) elif self.parameters['material']['p'] == 'neg': from plate_lib import ActuationOverNematicFoundationPneg actuation = ActuationOverNematicFoundationPneg( self.z, self.mesh, self.parameters, measures) else: raise NotImplementedError x = Expression(['x[0]', 'x[1]', '0.'], degree=0) self.load = Expression('s', s=1., degree=0) e1 = Constant([1, 0, 0]) e3 = Constant([0, 0, 1]) # self.n = Expression('sin(theta)*_e1 + cos(theta)*_e3', # _e1 = e1, _e3 = e3, theta = 0., degree = 0) self.n = Expression(['sin(theta)', 0, 'cos(theta)'], theta=0, degree=0) # import pdb; pdb.set_trace() # print('Nematic: {}'.format(self.parameters["material"]["nematic"])) if self.parameters["material"]["nematic"] == 'e1': n = e1 elif self.parameters["material"]["nematic"] == 'e3': n = e3 elif self.parameters["material"]["nematic"] == 'tilt': n = (e1 - e3) / np.sqrt(2) else: raise NotImplementedError Qn = outer(self.n, self.n) - 1. / 3. * Identity(3) actuation.Q0n = self.load * Qn self.Q0 = actuation.Q0n actuation.define_variational_equation() self.F = actuation.F self.J = actuation.jacobian self.energy_mem = actuation.energy_mem self.energy_ben = actuation.energy_ben self.energy_nem = actuation.energy_nem self.work = actuation.work
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 __init__(self, parameters, domain): rho = Constant(parameters["density [kg/m3]"]) mu = Constant(parameters["viscosity [Pa*s]"]) dt = Constant(parameters["dt [s]"]) u, u_1, p_1, vu = domain.u, domain.u_1, domain.p_1, domain.vu n = FacetNormal(domain.mesh) acceleration = rho*inner((u-u_1)/dt, vu) * dx convection = dot(div(rho*outer(u_1, u)), vu) * dx 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) pressure = inner(p_1, div(vu))*dx - dot(p_1*n, vu)*ds # int. by parts # TODO: what is better? # convection = rho*dot(dot(u_1, nabla_grad(u_k)), vu) * dx # diffusion = (mu*inner(grad(u_1), grad(vu))*dx # - mu*dot(nabla_grad(u_1)*n, vu)*ds) # int. by parts F_impl = - acceleration - convection + diffusion + pressure 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 forms_theta_nlinear_multiphase( self, rho, rho0, rho00, rhobar, v0, Ubar0, dt, theta_map, theta_L=Constant(1.0), duh0=Constant((0.0, 0.0)), duh00=Constant((0.0, 0)), h=Constant((0.0, 0.0)), neumann_idx=99, ): """ Set PDEMap forms for a non-linear (but linearized) advection problem including density. Parameters ---------- rho: dolfin.Function Current density field rho0: dolfin.Function Density field at previous time step. rho00: dolfin.Function Density field at second last time step rhobar: dolfin.Function Density field at facets v0: dolfin.Function Specific momentum at old time level Ubar0: dolfin.Function Advective field at old time level dt: Constant Time step theta_map: Constant Theta value for time stepping in PDE-projection according to theta-method **NOTE** theta only affects solution for Lagrange multiplier space polynomial order >= 1 theta_L: Constant, optional Theta value for reconstructing intermediate field from the previous solution and old increments. duh0: dolfin.Function, optional Increment from previous time step. duh00: dolfin.Function, optional Increment from second last time step h: Constant, dolfin.Function, optional Expression or Function for non-homogenous Neumann BC. Defaults to Constant(0. neumann_idx: int, optional Integer to use for marking Neumann boundaries. Defaults to value 99 Returns ------- dict Dict with forms """ (v, lamb, vbar) = self._trial_functions() (w, tau, wbar) = self._test_functions() (zero_vec, h, duh0, duh00) = self._check_geometric_dimension(h, duh0, duh00) beta_map = self.beta_map n = self.n facet_integral = self.facet_integral # FIXME: To be deprecated rhov_star = rho0 * (v0 + theta_L * duh0) + rho00 * (1 - theta_L) * duh00 Udiv = v0 + duh0 outer_v_a = outer(rho * w, Udiv) outer_v_a_o = outer(rho0 * Udiv, Udiv) outer_ubar_a = outer(rhobar * vbar, Ubar0) # Switch to detect in/outflow boundary gamma = conditional(ge(dot(Udiv, n), 0), 0, 1) # LHS contribution N_a = facet_integral(beta_map * dot(v, w)) G_a = ( dot(lamb, rho * w) / dt * dx - theta_map * inner(outer_v_a, grad(lamb)) * dx + theta_map * (1 - gamma) * dot(outer_v_a * n, lamb) * self.ds(neumann_idx) ) L_a = -facet_integral(beta_map * dot(vbar, w)) H_a = facet_integral(dot(outer_ubar_a * n, tau)) - dot(outer_ubar_a * n, tau) * self.ds( neumann_idx ) B_a = facet_integral(beta_map * dot(vbar, wbar)) # RHS contribution Q_a = dot(zero_vec, w) * dx R_a = ( dot(rhov_star, tau) / dt * dx + (1 - theta_map) * inner(outer_v_a_o, grad(tau)) * dx + gamma * dot(h, tau) * self.ds(neumann_idx) ) S_a = facet_integral(dot(zero_vec, wbar)) return self._fem_forms(N_a, G_a, L_a, H_a, B_a, Q_a, R_a, S_a)
def forms_theta_nlinear_np( self, v0, v_int, Ubar0, dt, theta_map=Constant(1.0), theta_L=Constant(1.0), duh0=Constant((0.0, 0.0)), duh00=Constant((0.0, 0)), h=Constant((0.0, 0.0)), neumann_idx=99, ): """ Set PDEMap forms for a non-linear (but linearized) advection problem, assumes however that the mass matrix can be obtained from the mesh (and not from particles) **NOTE** Documentation upcoming. """ # Define trial test functions (v, lamb, vbar) = self._trial_functions() (w, tau, wbar) = self._test_functions() (zero_vec, h, duh0, duh00) = self._check_geometric_dimension(h, duh0, duh00) beta_map = self.beta_map n = self.n facet_integral = self.facet_integral # Define v_star v_star = v0 + (1 - theta_L) * duh00 + theta_L * duh0 Udiv = v0 + duh0 outer_v_a = outer(w, Udiv) outer_v_a_o = outer(v_star, Udiv) outer_ubar_a = outer(vbar, Ubar0) # Switch to detect in/outflow boundary gamma = conditional(ge(dot(Udiv, n), 0), 0, 1) # LHS contribution s N_a = dot(v, w) * dx + facet_integral(beta_map * dot(v, w)) G_a = ( dot(lamb, w) / dt * dx - theta_map * inner(outer_v_a, grad(lamb)) * dx + theta_map * (1 - gamma) * dot(outer_v_a * n, lamb) * self.ds(neumann_idx) ) L_a = -facet_integral(beta_map * dot(vbar, w)) H_a = facet_integral(dot(outer_ubar_a * n, tau)) - dot(outer_ubar_a * n, tau) * self.ds( neumann_idx ) B_a = facet_integral(beta_map * dot(vbar, wbar)) # RHS contributions Q_a = dot(v_int, w) * dx R_a = ( dot(v_star, tau) / dt * dx + (1 - theta_map) * inner(outer_v_a_o, grad(tau)) * dx - gamma * dot(h, tau) * self.ds(neumann_idx) ) S_a = facet_integral(dot(Constant(zero_vec), wbar)) return self._fem_forms(N_a, G_a, L_a, H_a, B_a, Q_a, R_a, S_a)
def forms_theta_nlinear( self, v0, Ubar0, dt, theta_map=Constant(1.0), theta_L=Constant(1.0), duh0=Constant((0.0, 0.0)), duh00=Constant((0.0, 0)), h=Constant((0.0, 0.0)), neumann_idx=99, ): """ Set PDEMap forms for a non-linear (but linearized) advection problem, Parameters ---------- v0: dolfin.Function dolfin.Function storing solution from previous step Ubar0: dolfin.Function Advective velocity at facets dt: Constant Time step theta_map: Constant, optional Theta value for time stepping in PDE-projection according to theta-method. Defaults to Constant(1.) **NOTE** theta only affects solution for Lagrange multiplier space polynomial order >= 1 theta_L: Constant, optional Theta value for reconstructing intermediate field from the previous solution and old increments. Defaults to Constant(1.) duh0: dolfin.Function, optional Increment function from last time step duh00: dolfin.Function, optional Increment function from second last time step h: Constant, dolfin.Function, optional Expression or Function for non-homogenous Neumann BC. Defaults to Constant(0.) neumann_idx: int, optional Integer to use for marking Neumann boundaries. Defaults to value 99 Returns ------- dict Dictionary with forms """ # Define trial test functions (v, lamb, vbar) = self._trial_functions() (w, tau, wbar) = self._test_functions() (zero_vec, h, duh0, duh00) = self._check_geometric_dimension(h, duh0, duh00) beta_map = self.beta_map n = self.n facet_integral = self.facet_integral # Define v_star v_star = v0 + (1 - theta_L) * duh00 + theta_L * duh0 Udiv = v0 + duh0 outer_v_a = outer(w, Udiv) outer_v_a_o = outer(v_star, Udiv) outer_ubar_a = outer(vbar, Ubar0) # Switch to detect in/outflow boundary gamma = conditional(ge(dot(Udiv, n), 0), 0, 1) # LHS contribution s N_a = facet_integral(beta_map * dot(v, w)) G_a = ( dot(lamb, w) / dt * dx - theta_map * inner(outer_v_a, grad(lamb)) * dx + theta_map * (1 - gamma) * dot(outer_v_a * n, lamb) * self.ds(neumann_idx) ) L_a = -facet_integral(beta_map * dot(vbar, w)) H_a = facet_integral(dot(outer_ubar_a * n, tau)) - dot(outer_ubar_a * n, tau) * self.ds( neumann_idx ) B_a = facet_integral(beta_map * dot(vbar, wbar)) # RHS contributions Q_a = dot(zero_vec, w) * dx R_a = ( dot(v_star, tau) / dt * dx + (1 - theta_map) * inner(outer_v_a_o, grad(tau)) * dx - gamma * dot(h, tau) * self.ds(neumann_idx) ) S_a = facet_integral(dot(zero_vec, wbar)) return self._fem_forms(N_a, G_a, L_a, H_a, B_a, Q_a, R_a, S_a)
def NSPFEC_action(u_, u_1, phi_, phi_1, c_, c_1, u, p, phi, g, c, V, v, q, psi, h, b, U, rho, M, nu, rho_e, K, veps, drho, grav, sigma_bar, eps, dveps, dbeta, z, per_tau, enable_NS, enable_PF, enable_EC): # The setup of the Navier-Stokes part of F F = [] if enable_NS: F_NS = (per_tau * rho * df.dot(u_ - u_1, v) * df.dx + df.inner( df.grad(u), df.outer(rho * u - drho * M * df.grad(g), v)) * df.dx + 2 * nu * df.inner(df.sym(df.grad(u)), df.grad(v)) * df.dx - p * df.div(v) * df.dx + df.div(u) * q * df.dx - df.dot(rho * grav, v) * df.dx) if enable_PF: F_NS += -sigma_bar * eps * df.inner( df.outer(df.grad(phi), df.grad(phi)), df.grad(v)) * df.dx if enable_EC and rho_e != 0: F_NS += rho_e * df.dot(df.grad(V), v) * df.dx if enable_PF and enable_EC: F_NS += dveps * df.dot(df.grad(phi), v) * df.dot( df.grad(V), df.grad(V)) * df.dx F.append(F_NS) # The setup of the Phase feild equations if enable_PF: F_PF_phi = (per_tau * (phi_ - phi_1) * psi * df.dx + M * df.dot(df.grad(g), df.grad(psi)) * df.dx) if enable_NS: F_PF_phi += df.dot(u, df.grad(phi)) * psi * df.dx F_PF_g = (g * h * df.dx - sigma_bar * eps * df.dot(df.grad(phi), df.grad(h)) * df.dx - sigma_bar / eps * diff_pf_potential(phi) * h * df.dx) if enable_EC: F_PF_g += (-sum( [dbeta_i * ci * h * df.dx for dbeta_i, ci in zip(dbeta, c)]) + dveps * df.dot(df.grad(V), df.grad(V)) * h * df.dx) F_PF = F_PF_phi + F_PF_g F.append(F_PF) # The setup of the Electrochemistry if enable_EC: F_E_c = [] for ci, ci_, ci_1, bi, Ki, zi in zip(c, c_, c_1, b, K, z): F_E_ci = (per_tau * (ci_ - ci_1) * 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 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 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, 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 define_coupled_equation(self): """ Setup the coupled Navier-Stokes equation This implementation assembles the full LHS and RHS each time they are needed """ sim = self.simulation mpm = sim.multi_phase_model mesh = sim.data['mesh'] Vcoupled = sim.data['Vcoupled'] u_conv = sim.data['u_conv'] # Unpack the coupled trial and test functions uc = dolfin.TrialFunction(Vcoupled) vc = dolfin.TestFunction(Vcoupled) ulist = [] vlist = [] sigmas, taus = [], [] for d in range(sim.ndim): ulist.append(uc[d]) vlist.append(vc[d]) indices = list( range(1 + sim.ndim * (d + 1), 1 + sim.ndim * (d + 2))) sigmas.append([uc[i] for i in indices]) taus.append([vc[i] for i in indices]) u = dolfin.as_vector(ulist) v = dolfin.as_vector(vlist) p = uc[sim.ndim] q = vc[sim.ndim] sigma = dolfin.as_tensor(sigmas) tau = dolfin.as_tensor(taus) c1, c2, c3 = sim.data['time_coeffs'] dt = sim.data['dt'] g = sim.data['g'] n = dolfin.FacetNormal(mesh) h = dolfin.FacetArea(mesh) # Fluid properties rho = mpm.get_density(0) mu = mpm.get_laminar_dynamic_viscosity(0) # Upwind and downwind velocities w_nU = (dot(u_conv, n) + abs(dot(u_conv, n))) / 2.0 w_nD = (dot(u_conv, n) - abs(dot(u_conv, n))) / 2.0 u_uw_s = dolfin.conditional(dolfin.gt(dot(u_conv, n), 0.0), 1.0, 0.0)('+') u_uw = u_uw_s * u('+') + (1 - u_uw_s) * u('-') # LDG penalties # kappa_0 = Constant(4.0) # kappa = mu*kappa_0/h C11 = avg(mu / h) D11 = avg(h / mu) C12 = 0.2 * n('+') D12 = 0.2 * n('+') def ojump(v, n): return outer(v, n)('+') + outer(v, n)('-') # Interior facet fluxes # u_hat_dS = avg(u) # sigma_hat_dS = avg(sigma) - avg(kappa)*ojump(u, n) # p_hat_dS = avg(p) u_hat_s_dS = avg(u) + dot(ojump(u, n), C12) u_hat_p_dS = avg(u) + D11 * jump(p, n) + D12 * jump(u, n) sigma_hat_dS = avg(sigma) - C11 * ojump(u, n) - outer( jump(sigma, n), C12) p_hat_dS = avg(p) - dot(D12, jump(p, n)) # Time derivative up = sim.data['up'] upp = sim.data['upp'] eq = rho * dot(c1 * u + c2 * up + c3 * upp, v) / dt * dx # LDG equation 1 eq += inner(sigma, tau) * dx eq += dot(u, div(mu * tau)) * dx eq -= dot(u_hat_s_dS, jump(mu * tau, n)) * dS # LDG equation 2 eq += (inner(sigma, grad(v)) - p * div(v)) * dx eq -= (inner(sigma_hat_dS, ojump(v, n)) - p_hat_dS * jump(v, n)) * dS eq -= dot(u, div(outer(v, rho * u_conv))) * dx eq += rho('+') * dot(u_conv('+'), n('+')) * dot(u_uw, v('+')) * dS eq += rho('-') * dot(u_conv('-'), n('-')) * dot(u_uw, v('-')) * dS momentum_sources = sim.data['momentum_sources'] + [rho * g] eq -= dot(sum(momentum_sources), v) * dx # LDG equation 3 eq -= dot(u, grad(q)) * dx eq += dot(u_hat_p_dS, jump(q, n)) * dS # Dirichlet boundary dirichlet_bcs = get_collected_velocity_bcs(sim, 'dirichlet_bcs') for ds, u_bc in dirichlet_bcs.items(): # sigma_hat_ds = sigma - kappa*outer(u, n) sigma_hat_ds = sigma - C11 * outer(u - u_bc, n) u_hat_ds = u_bc p_hat_ds = p # LDG equation 1 eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds # LDG equation 2 eq -= (inner(sigma_hat_ds, outer(v, n)) - p_hat_ds * dot(v, n)) * ds eq += rho * w_nU * dot(u, v) * ds eq += rho * w_nD * dot(u_bc, v) * ds # LDG equation 3 eq += dot(u_hat_ds, q * n) * ds # Neumann boundary neumann_bcs = get_collected_velocity_bcs(sim, 'neumann_bcs') assert not neumann_bcs for ds, du_bc in neumann_bcs.items(): # Divergence free criterion if self.use_grad_q_form: eq += q * dot(u, n) * ds else: eq -= q * dot(u, n) * ds # Convection eq += rho * w_nU * dot(u, v) * ds # Diffusion u_hat_ds = u sigma_hat_ds = outer(du_bc, n) / mu eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds eq -= inner(sigma_hat_ds, outer(v, n)) * ds # Pressure if not self.use_grad_p_form: eq += p * dot(v, n) * ds a, L = dolfin.system(eq) self.form_lhs = a self.form_rhs = L self.tensor_lhs = None self.tensor_rhs = None
def solve_initial_pressure(w_NSp, p, q, u, v, dx, ds, dirichlet_bcs_NSp, neumann_bcs, boundary_to_mark, M_, g_, phi_, rho_, rho_e_, V_, drho, sigma_bar, eps, grav, dveps, enable_PF, enable_EC, use_iterative_solvers, solve_initial=True): if solve_initial: V = u.function_space() grad_p = df.TrialFunction(V) grad_p_out = df.Function(V) F_grad_p = (df.dot(grad_p, v) * dx - rho_ * df.dot(grav, v) * dx) if enable_PF: F_grad_p += -drho * M_ * df.inner(df.grad(u), df.outer(df.grad(g_), v)) * dx F_grad_p += -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_grad_p += rho_e_ * df.dot(df.grad(V_), v) * dx if enable_PF and enable_EC: F_grad_p += 0.5 * dveps * df.dot(df.grad(phi_), v) * df.dot( df.grad(V_), df.grad(V_)) * dx info_red("Solving initial grad_p...") problem_grad_p = df.LinearVariationalProblem(df.lhs(F_grad_p), df.rhs(F_grad_p), grad_p_out) # df.solve(df.lhs(F_grad_p) == df.rhs(F_grad_p), grad_p_out) solver_grad_p = df.LinearVariationalSolver(problem_grad_p) if use_iterative_solvers: solver_grad_p.parameters["linear_solver"] = "gmres" solver_grad_p.parameters["preconditioner"] = "amg" solver_grad_p.solve() F_p = (df.dot(df.grad(q), df.grad(p)) * dx - df.dot(df.grad(q), grad_p_out) * dx) info_red("Solving initial p...") problem_p = df.LinearVariationalProblem(df.lhs(F_p), df.rhs(F_p), w_NSp, dirichlet_bcs_NSp) # df.solve(df.lhs(F_p) == df.rhs(F_p), w_NSp, dirichlet_bcs_NSp) solver_p = df.LinearVariationalSolver(problem_p) if use_iterative_solvers: solver_p.parameters["linear_solver"] = "gmres" solver_p.parameters["preconditioner"] = "amg" solver_p.solve() info_red("Done with the initials.")
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
# total_mass = assemble(rho * dx) mass_change_noflux = assemble((rho - rho0) * dx) mass_change_flux = assemble((rho - rho0) * dx + dt * dot(ubar0_a, n) * rhobar * ds(98)) mx_change_noflux = assemble( (rho * dot(ustar, ex) - dot(rho0 * Uh.sub(0), ex)) * dx) my_change_noflux = assemble( (rho * dot(ustar, ey) - dot(rho0 * Uh.sub(0), ey)) * dx) mt_change_noflux = mx_change_noflux + my_change_noflux # Check (global) momentum conservation mx_change = assemble( (rho * dot(ustar, ex) - dot(rho0 * Uh.sub(0), ex)) * dx + dt * dot(outer(rhobar * ustar_bar, ubar0_a) * n, ex) * ds) my_change = assemble( (rho * dot(ustar, ey) - dot(rho0 * Uh.sub(0), ey)) * dx + dt * dot(outer(rhobar * ustar_bar, ubar0_a) * n, ey) * ds) mt_change = mx_change + my_change # Compute Rho_min and Rho_max rho_proc_0 = rho.vector().gather_on_zero() if comm.rank == 0: rho_min = np.amin(rho_proc_0) rho_max = np.amax(rho_proc_0) with open(conservation_data, "a") as write_file: data = [ t, total_mass, mass_change_flux, mass_change_noflux, mt_change,
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 }
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 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)) 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}
def ojump(v, n): return outer(v, n)('+') + outer(v, n)('-')
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 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