Пример #1
0
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.)
Пример #2
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()
Пример #3
0
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
Пример #4
0
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)