def regulate(ci, ci_1, EC_scheme, c_cutoff): if EC_scheme in ["NL1", "NL2"]: return max_value(ci, 0.) elif EC_scheme == ["L2"]: return max_value(ci_1, c_cutoff) else: return max_value(ci_1, 0.)
def equilibrium_EC(w_, test_functions, solutes, permittivity, dx, ds, normal, dirichlet_bcs, neumann_bcs, boundary_to_mark, use_iterative_solvers, V_lagrange, **namespace): """ Electrochemistry equilibrium solver. Nonlinear! """ num_solutes = len(solutes) cV = df.split(w_["EC"]) c, V = cV[:num_solutes], cV[num_solutes] if V_lagrange: V0 = cV[-1] b = test_functions["EC"][:num_solutes] U = test_functions["EC"][num_solutes] if V_lagrange: U0 = test_functions["EC"][-1] z = [] # Charge z[species] K = [] # Diffusivity K[species] for solute in solutes: z.append(solute[1]) K.append(solute[2]) rho_e = sum([c_e*z_e for c_e, z_e in zip(c, z)]) veps = permittivity[0] F_c = [] for ci, bi, Ki, zi in zip(c, b, K, z): grad_g_ci = df.grad(alpha_c(ci) + zi*V) F_ci = Ki*max_value(ci, 0.)*df.dot(grad_g_ci, df.grad(bi))*dx F_c.append(F_ci) F_V = veps*df.dot(df.grad(V), df.grad(U))*dx for boundary_name, sigma_e in neumann_bcs["V"].iteritems(): F_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) if rho_e != 0: F_V += -rho_e*U*dx if V_lagrange: F_V += veps*V0*U*dx + veps*V*U0*dx F = sum(F_c) + F_V J = df.derivative(F, w_["EC"]) problem = df.NonlinearVariationalProblem(F, w_["EC"], dirichlet_bcs["EC"], J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-7 if use_iterative_solvers: solver.parameters["newton_solver"]["linear_solver"] = "bicgstab" if not V_lagrange: solver.parameters["newton_solver"]["preconditioner"] = "hypre_amg" solver.solve()
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 pf_mobility(phi, gamma): """ Phase field mobility function. """ # return gamma * (phi**2-1.)**2 func = 1.-phi**2 return 0.75 * gamma * max_value(0., func)