Domain: Chemistry — Physical Chemistry

Problem:
Compute a single numeric quantity from a steady one-dimensional Poisson–Nernst–Planck (PNP) equilibrium (zero net flux) across a nanoslab of thickness \(L=2.00\times10^{-7}\ \text{m}\) with coordinate \(x\in[0,L]\). Symmetric \(1{:}1\) electrolyte with mobile ions \(c_+(x)\) and \(c_-(x)\); nonuniform fixed volumetric charge \(w(x)=w_0\,[1+\mathcal{A}\cos(\pi x/L)]\) with \(w_0=0.500\ \text{mol}\cdot\text{m}^{-3}\) and \(\mathcal{A}=0.20\); ideal activities \(\ln\gamma_i=0\).

Constants (SI): \(F=9.648533212\times10^{4}\ \text{C}\cdot\text{mol}^{-1}\), \(R=8.314462618\ \text{J}\cdot\text{mol}^{-1}\cdot\text{K}^{-1}\), \(T=298.15\ \text{K}\), \(\alpha=F/(RT)\ \text{V}^{-1}\); \(\varepsilon_r=78.5\); \(\varepsilon_0=8.8541878128\times10^{-12}\ \text{F}\cdot\text{m}^{-1}\); \(\varepsilon=\varepsilon_r\varepsilon_0\). Diffusivities: \(D_+=1.5\times10^{-9}\ \text{m}^{2}\cdot\text{s}^{-1}\), \(D_-=2.0\times10^{-9}\ \text{m}^{2}\cdot\text{s}^{-1}\). Left bath concentration: \(c_L=50.000\ \text{mol}\cdot\text{m}^{-3}\). Applied voltage: \(\Delta V=\phi(L)-\phi(0)=-0.25\ \text{V}\).

Non-dimensionalization: \(\lambda_D=\sqrt{\varepsilon RT/(2F^{2}c_L)}\), \(\xi=x/\lambda_D\), \(\Lambda=L/\lambda_D\); define \(n(\xi)=\tfrac{c_+(x)+c_-(x)}{2c_L}\), \(\rho(\xi)=\tfrac{c_+(x)-c_-(x)}{2c_L}\), \(\psi(\xi)=\alpha\,\phi(x)\), \(\Psi(\xi)=d\psi/d\xi\), and \(\omega(\xi)=\dfrac{w(x)}{2c_L}=\omega_0\,[1+\mathcal{A}\cos(\pi\,\xi/\Lambda)]\) with \(\omega_0=w_0/(2c_L)\). Then \(c_{\pm}(x)=c_L\,(n\pm\rho)\).

Governing nondimensional PNP equations:
\[
\frac{dn}{d\xi}=-\Psi\,\rho,\quad
\frac{d\rho}{d\xi}=-\Psi\,n,\quad
\frac{d\psi}{d\xi}=\Psi,\quad
\frac{d\Psi}{d\xi}=-(\rho+\omega(\xi)).
\]

Boundary conditions: \(n(0)=1,\ \rho(0)=0,\ \psi(0)=0,\ \psi(\Lambda)=\alpha\,\Delta V\).

Use a robust boundary-value solver with a smooth boundary-refined mesh and continuation in \(\Delta\psi\) from \(0\) to \(\alpha\Delta V\). 

Reconstruct the electric field \(E(x)=\Psi(\xi)/(\alpha\,\lambda_D)\) and compute the left surface charge density \(\sigma_0=-\varepsilon\,E(0)\) in \(\text{C}\cdot\text{m}^{-2}\). 

Create a single computational task to implement and report only the numeric value of \(\sigma_0\) in scientific notation with three significant figures (e.g., \(1.00\times10^{x}\)).

Answer: \( -7.88\times10^{-5} \)

Solution code:
# -*- coding: utf-8 -*-
# Clean version — single public function `solution()` with all helpers nested.
# Prints ONLY one numeric line (scientific notation, three significant figures).
# Steady nondimensional PNP with nonuniform fixed charge ω(ξ) = ω0[1 + A cos(π ξ / Λ)].

import numpy as np
from scipy.integrate import solve_bvp, cumulative_trapezoid

def solution():
    # -----------------------------
    # Physical constants (SI)
    # -----------------------------
    F     = 9.648533212e4           # C·mol^-1
    R     = 8.314462618             # J·mol^-1·K^-1
    T     = 298.15                  # K
    alpha = F/(R*T)                 # V^-1
    eps0  = 8.8541878128e-12        # F·m^-1

    # -----------------------------
    # Problem parameters (SI)
    # -----------------------------
    L        = 2.00e-7              # m
    DeltaV   = -2.50e-1             # V
    cL       = 50.000               # mol·m^-3
    eps_r    = 78.5
    eps      = eps_r * eps0         # F·m^-1
    w0_SI    = 0.500                # mol·m^-3
    A_omega  = 0.20                 # amplitude in ω(ξ)

    # -----------------------------
    # Nondimensional scales
    # -----------------------------
    lambda_D  = np.sqrt(eps*R*T/(2.0*F*F*cL))
    Lambda    = L / lambda_D
    Delta_psi_target = alpha * DeltaV
    omega0    = w0_SI/(2.0*cL)      # base nondimensional fixed charge

    # -----------------------------
    # Boundary-refined mesh (CDF of symmetric tanh weight)
    # -----------------------------
    def stretched_mesh_nd(Lambda_val, N_nodes=1800, stretch_units=4.5):
        xi_unit = np.linspace(0.0, 1.0, N_nodes)
        a = max(min(stretch_units / Lambda_val, 0.3), 1e-3)
        s = 6.0
        left  = 0.5*(1.0 - np.tanh(s*(xi_unit - a))/np.tanh(s*a))
        right = 0.5*(1.0 + np.tanh(s*(xi_unit - (1.0 - a)))/np.tanh(s*a))
        w = left + right
        w_int = cumulative_trapezoid(w, xi_unit, initial=0.0)
        w_int = (w_int - w_int[0])/(w_int[-1] - w_int[0])
        xi = w_int * Lambda_val
        xi[1:] = np.maximum(xi[1:], xi[:-1] + 1e-12)
        return xi

    # -----------------------------
    # ω(ξ) = ω0 [1 + A cos(π ξ / Λ)]
    # -----------------------------
    def omega_xi(xi):
        return omega0 * (1.0 + A_omega * np.cos(np.pi * xi / Lambda))

    # -----------------------------
    # ND PNP ODEs with nonuniform ω(ξ)
    # -----------------------------
    def pnp_fun_adim(xi, y):
        n, rho, psi, Psi = y
        dn   = - Psi * rho
        drho = - Psi * n
        dpsi = Psi
        dPsi = - (rho + omega_xi(xi))
        return np.vstack((dn, drho, dpsi, dPsi))

    # -----------------------------
    # Boundary conditions: n(0)=1, ρ(0)=0, ψ(0)=0, ψ(Λ)=Δψ_now
    # -----------------------------
    def pnp_bc_adim(ya, yb, Delta_psi_now):
        n0, rho0, psi0, Psi0 = ya
        nL, rhoL, psiL, PsiL = yb
        return np.array([n0 - 1.0, rho0, psi0, psiL - Delta_psi_now])

    # -----------------------------
    # Smooth initial guess
    # -----------------------------
    def pnp_guess_trivial(xi):
        n   = np.ones_like(xi)
        rho = np.zeros_like(xi)
        psi = np.zeros_like(xi)
        Psi = np.zeros_like(xi)
        return np.vstack((n, rho, psi, Psi))

    # -----------------------------
    # Continuation in Δψ from 0 to target
    # -----------------------------
    def solve_with_continuation():
        N_coarse, N_refine = 900, 1800
        stretch_units = 4.5
        tol_coarse, tol_refine = 1e-6, 1e-8
        max_nodes = 120000

        # coarse at Δψ=0
        xi_c = stretched_mesh_nd(Lambda, N_coarse, stretch_units)
        y0_c = pnp_guess_trivial(xi_c)
        sol_c = solve_bvp(pnp_fun_adim, lambda ya, yb: pnp_bc_adim(ya, yb, 0.0),
                          xi_c, y0_c, tol=tol_coarse, max_nodes=max_nodes, verbose=0)
        if not sol_c.success:
            return None

        # refine at Δψ=0
        xi_r = stretched_mesh_nd(Lambda, N_refine, stretch_units)
        y0_r = sol_c.sol(xi_r)
        sol_r = solve_bvp(pnp_fun_adim, lambda ya, yb: pnp_bc_adim(ya, yb, 0.0),
                          xi_r, y0_r, tol=tol_refine, max_nodes=max_nodes, verbose=0)
        if not sol_r.success:
            return None

        # continuation path
        steps = 40
        psi_path = np.linspace(0.0, Delta_psi_target, steps+1)[1:]
        sol_curr = sol_r
        for dpsi in psi_path:
            xi_r = stretched_mesh_nd(Lambda, N_refine, stretch_units)
            y0_r = sol_curr.sol(xi_r)
            sol_curr = solve_bvp(pnp_fun_adim,
                                 lambda ya, yb, dpsi=dpsi: pnp_bc_adim(ya, yb, dpsi),
                                 xi_r, y0_r, tol=tol_refine, max_nodes=max_nodes, verbose=0)
            if not sol_curr.success:
                return None
        return sol_curr

    # -----------------------------
    # Solve and print σ0 (scientific notation, three significant figures)
    # -----------------------------
    try:
        sol = solve_with_continuation()
        if sol is None or (not sol.success):
            print(f"{float('nan'):.2e}")
            return
        Psi0 = float(sol.sol(0.0)[3])
        E0   = Psi0/(alpha*lambda_D)
        sigma0 = -eps * E0
        print(f"{sigma0:.2e}")
    except Exception:
        print(f"{float('nan'):.2e}")

# Call the single public function as requested (no if-guard).
solution()