Source code for pygbe.util.an_solution

"""
It contains the functions to compute the cases that presents an analytical
solutions.
All functions output the analytical solution in kcal/mol
"""
import numpy
from numpy import pi
from scipy import special, linalg
from scipy.misc import factorial
from math import gamma


[docs]def an_spherical(q, xq, E_1, E_2, E_0, R, N): """ It computes the analytical solution of the potential of a sphere with Nq charges inside. Took from Kirkwood (1934). Arguments ---------- q : array, charges. xq : array, positions of the charges. E_1: float, dielectric constant inside the sphere. E_2: float, dielectric constant outside the sphere. E_0: float, dielectric constant of vacuum. R : float, radius of the sphere. N : int, number of terms desired in the spherical harmonic expansion. Returns -------- PHI: array, reaction potential. """ PHI = numpy.zeros(len(q)) for K in range(len(q)): rho = numpy.sqrt(numpy.sum(xq[K]**2)) zenit = numpy.arccos(xq[K, 2] / rho) azim = numpy.arctan2(xq[K, 1], xq[K, 0]) phi = 0. + 0. * 1j for n in range(N): for m in range(-n, n + 1): sph1 = special.sph_harm(m, n, zenit, azim) cons1 = rho**n / (E_1 * E_0 * R**(2 * n + 1)) * (E_1 - E_2) * ( n + 1) / (E_1 * n + E_2 * (n + 1)) cons2 = 4 * pi / (2 * n + 1) for k in range(len(q)): rho_k = numpy.sqrt(numpy.sum(xq[k]**2)) zenit_k = numpy.arccos(xq[k, 2] / rho_k) azim_k = numpy.arctan2(xq[k, 1], xq[k, 0]) sph2 = numpy.conj(special.sph_harm(m, n, zenit_k, azim_k)) phi += cons1 * cons2 * q[K] * rho_k**n * sph1 * sph2 PHI[K] = numpy.real(phi) / (4 * pi)
return PHI
[docs]def get_K(x, n): """ It computes the polinomials K needed for Kirkwood-1934 solutions. K_n(x) in Equation 4 in Kirkwood 1934. Arguments ---------- x: float, evaluation point of K. n: int, number of terms desired in the expansion. Returns -------- K: float, polinomials K. """ K = 0. n_fact = factorial(n) n_fact2 = factorial(2 * n) for s in range(n + 1): K += 2**s * n_fact * factorial(2 * n - s) / (factorial(s) * n_fact2 * factorial(n - s)) * x**s
return K
[docs]def an_P(q, xq, E_1, E_2, R, kappa, a, N): """ It computes the solvation energy according to Kirkwood-1934. Arguments ---------- q : array, charges. xq : array, positions of the charges. E_1 : float, dielectric constant inside the sphere. E_2 : float, dielectric constant outside the sphere. R : float, radius of the sphere. kappa: float, reciprocal of Debye length. a : float, radius of the Stern Layer. N : int, number of terms desired in the polinomial expansion. Returns -------- E_P : float, solvation energy. """ qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 PHI = numpy.zeros(len(q)) for K in range(len(q)): rho = numpy.sqrt(numpy.sum(xq[K]**2)) zenit = numpy.arccos(xq[K, 2] / rho) azim = numpy.arctan2(xq[K, 1], xq[K, 0]) phi = 0. + 0. * 1j for n in range(N): for m in range(-n, n + 1): P1 = special.lpmv(numpy.abs(m), n, numpy.cos(zenit)) Enm = 0. for k in range(len(q)): rho_k = numpy.sqrt(numpy.sum(xq[k]**2)) zenit_k = numpy.arccos(xq[k, 2] / rho_k) azim_k = numpy.arctan2(xq[k, 1], xq[k, 0]) P2 = special.lpmv(numpy.abs(m), n, numpy.cos(zenit_k)) Enm += q[k] * rho_k**n * factorial(n - numpy.abs( m)) / factorial(n + numpy.abs(m)) * P2 * numpy.exp( -1j * m * azim_k) C2 = (kappa * a)**2 * get_K(kappa * a, n - 1) / ( get_K(kappa * a, n + 1) + n * (E_2 - E_1) / ( (n + 1) * E_2 + n * E_1) * (R / a)**(2 * n + 1) * (kappa * a)**2 * get_K(kappa * a, n - 1) / ((2 * n - 1) * (2 * n + 1))) C1 = Enm / (E_2 * E_0 * a** (2 * n + 1)) * (2 * n + 1) / (2 * n - 1) * (E_2 / ( (n + 1) * E_2 + n * E_1))**2 if n == 0 and m == 0: Bnm = Enm / (E_0 * R) * ( 1 / E_2 - 1 / E_1) - Enm * kappa * a / ( E_0 * E_2 * a * (1 + kappa * a)) else: Bnm = 1. / (E_1 * E_0 * R**(2 * n + 1)) * (E_1 - E_2) * ( n + 1) / (E_1 * n + E_2 * (n + 1)) * Enm - C1 * C2 phi += Bnm * rho**n * P1 * numpy.exp(1j * m * azim) PHI[K] = numpy.real(phi) / (4 * pi) C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J) E_P = 0.5 * C0 * numpy.sum(q * PHI)
return E_P
[docs]def two_sphere(a, R, kappa, E_1, E_2, q): """ It computes the analytical solution of a spherical surface and a spherical molecule with a center charge, both of radius R. Follows Cooper&Barba 2016 Arguments ---------- a : float, center to center distance. R : float, radius of surface and molecule. kappa: float, reciprocal of Debye length. E_1 : float, dielectric constant inside the sphere. E_2 : float, dielectric constant outside the sphere. q : float, number of qe to be asigned to the charge. Returns -------- Einter : float, interaction energy. E1sphere: float, solvation energy of one sphere. E2sphere: float, solvation energy of two spheres together. Note: Einter should match (E2sphere - 2xE1sphere) """ N = 20 # Number of terms in expansion. qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * a) K1p = index / (kappa * a) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * a) * numpy.sqrt(pi / (2 * kappa * a)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * a)**(3 / 2.)) * special.kv( index, kappa * a) + numpy.sqrt(pi / (2 * kappa * a)) * K1p I1 = special.iv(index2, kappa * a) I1p = index / (kappa * a) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * a) * numpy.sqrt(pi / (2 * kappa * a)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * a)**(3 / 2.)) * special.iv( index, kappa * a) + numpy.sqrt(pi / (2 * kappa * a)) * I1p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB M = numpy.zeros((N, N), float) E_hat = E_1 / E_2 for i in range(N): for j in range(N): M[i, j] = (2 * i + 1) * B[i, j] * ( kappa * i1p[i] - E_hat * i * i1[i] / a) if i == j: M[i, j] += kappa * k1p[i] - E_hat * i * k1[i] / a RHS = numpy.zeros(N) RHS[0] = -E_hat * q / (4 * pi * E_1 * a * a) a_coeff = linalg.solve(M, RHS) a0 = a_coeff[0] a0_inf = -E_hat * q / (4 * pi * E_1 * a * a) * 1 / (kappa * k1p[0]) phi_2 = a0 * k1[0] + i1[0] * numpy.sum(a_coeff * B[:, 0]) - q / (4 * pi * E_1 * a) phi_1 = a0_inf * k1[0] - q / (4 * pi * E_1 * a) phi_inter = phi_2 - phi_1 CC0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) Einter = 0.5 * CC0 * q * phi_inter E1sphere = 0.5 * CC0 * q * phi_1 E2sphere = 0.5 * CC0 * q * phi_2
return Einter, E1sphere, E2sphere
[docs]def constant_potential_single_point(phi0, a, r, kappa): """ It computes the potential in a point 'r' due to a spherical surface with constant potential phi0, immersed in water. Solution to the Poisson-Boltzmann problem. Arguments ---------- phi0 : float, constant potential on the surface of the sphere. a : float, radius of the sphere. r : float, distance from the center of the sphere to the evaluation point. kappa: float, reciprocal of Debye length. Returns -------- phi : float, potential. """ phi = a / r * phi0 * numpy.exp(kappa * (a - r))
return phi
[docs]def constant_charge_single_point(sigma0, a, r, kappa, epsilon): """ It computes the potential in a point 'r' due to a spherical surface with constant charge sigma0 immersed in water. Solution to the Poisson-Boltzmann problem. . Arguments ---------- sigma0 : float, constant charge on the surface of the sphere. a : float, radius of the sphere. r : float, distance from the center of the sphere to the evaluation point. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- phi : float, potential. """ dphi0 = -sigma0 / epsilon phi = -dphi0 * a * a / (1 + kappa * a) * numpy.exp(kappa * (a - r)) / r
return phi
[docs]def constant_potential_single_charge(phi0, radius, kappa, epsilon): """ It computes the surface charge of a sphere at constant potential, immersed in water. Arguments ---------- phi0 : float, constant potential on the surface of the sphere. radius : float, radius of the sphere. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant . Returns -------- sigma : float, surface charge. """ dphi = -phi0 * ((1. + kappa * radius) / radius) sigma = -epsilon * dphi # Surface charge
return sigma
[docs]def constant_charge_single_potential(sigma0, radius, kappa, epsilon): """ It computes the surface potential on a sphere at constant charged, immersed in water. Arguments ---------- sigma0 : float, constant charge on the surface of the sphere. radius : float, radius of the sphere. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- phi : float, potential. """ dphi = -sigma0 / epsilon phi = -dphi * radius / (1. + kappa * radius) # Surface potential
return phi
[docs]def constant_potential_twosphere(phi01, phi02, r1, r2, R, kappa, epsilon): """ It computes the solvation energy of two spheres at constant potential, immersed in water. Arguments ---------- phi01 : float, constant potential on the surface of the sphere 1. phi02 : float, constant potential on the surface of the sphere 2. r1 : float, radius of sphere 1. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E_solv : float, solvation energy. """ kT = 4.1419464e-21 # at 300K qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 C0 = kT / qe phi01 /= C0 phi02 /= C0 k1 = special.kv(0.5, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k2 = special.kv(0.5, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) B00 = special.kv(0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) # k1 = special.kv(0.5,kappa*r1)*numpy.sqrt(2/(pi*kappa*r1)) # k2 = special.kv(0.5,kappa*r2)*numpy.sqrt(2/(pi*kappa*r2)) # B00 = special.kv(0.5,kappa*R)*numpy.sqrt(2/(pi*kappa*R)) i1 = special.iv(0.5, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i2 = special.iv(0.5, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) a0 = (phi02 * B00 * i1 - phi01 * k2) / (B00 * B00 * i2 * i1 - k1 * k2) b0 = (phi02 * k1 - phi01 * B00 * i2) / (k2 * k1 - B00 * B00 * i1 * i2) U1 = 2 * pi * phi01 * (phi01 * numpy.exp(kappa * r1) * (kappa * r1) * (kappa * r1) / numpy.sinh(kappa * r1) - pi * a0 / (2 * i1)) U2 = 2 * pi * phi02 * (phi02 * numpy.exp(kappa * r2) * (kappa * r2) * (kappa * r2) / numpy.sinh(kappa * r2) - pi * b0 / (2 * i2)) print('U1: {}'.format(U1)) print('U2: {}'.format(U2)) print('E: {}'.format(U1 + U2)) C1 = C0 * C0 * epsilon / kappa u1 = U1 * C1 u2 = U2 * C1 CC0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E_solv = CC0 * (u1 + u2)
return E_solv
[docs]def constant_potential_twosphere_2(phi01, phi02, r1, r2, R, kappa, epsilon): """ It computes the solvation energy of two spheres at constant potential, immersed in water. Arguments ---------- phi01 : float, constant potential on the surface of the sphere 1. phi02 : float, constant potential on the surface of the sphere 2. r1 : float, radius of sphere 1. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E_solv : float, solvation energy. """ kT = 4.1419464e-21 # at 300K qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 h = R - r1 - r2 # E_inter = r1*r2*epsilon/(4*R) * ( (phi01+phi02)**2 * log(1+numpy.exp(-kappa*h)) + (phi01-phi02)**2*log(1-numpy.exp(-kappa*h)) ) # E_inter = epsilon*r1*phi01**2/2 * log(1+numpy.exp(-kappa*h)) E_solv = epsilon * r1 * r2 * (phi01**2 + phi02**2) / (4 * (r1 + r2)) * ( (2 * phi01 * phi02) / (phi01**2 + phi02**2) * log( (1 + numpy.exp(-kappa * h)) / (1 - numpy.exp(-kappa * h))) + log(1 - numpy.exp(-2 * kappa * h))) CC0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E_solv *= CC0
return E_solv
[docs]def constant_potential_single_energy(phi0, r1, kappa, epsilon): """ It computes the total energy of a single sphere at constant potential, inmmersed in water. Arguments ---------- phi0 : float, constant potential on the surface of the sphere. r1 : float, radius of sphere. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E : float, total energy. """ N = 1 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p a0_inf = phi0 / k1[0] U1_inf = a0_inf * k1p[0] C1 = 2 * pi * kappa * phi0 * r1 * r1 * epsilon C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E = C0 * C1 * U1_inf
return E
[docs]def constant_charge_single_energy(sigma0, r1, kappa, epsilon): """ It computes the total energy of a single sphere at constant charge, inmmersed in water. Arguments ---------- sigma0 : float, constant charge on the surface of the sphere. r1 : float, radius of sphere. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E : float, total energy. """ N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p a0_inf = -sigma0 / (epsilon * kappa * k1p[0]) U1_inf = a0_inf * k1[0] C1 = 2 * pi * sigma0 * r1 * r1 C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E = C0 * C1 * U1_inf
return E
[docs]def constant_potential_twosphere_dissimilar(phi01, phi02, r1, r2, R, kappa, epsilon): """ It computes the interaction energy for dissimilar spheres at constant potential, immersed in water. Arguments ---------- phi01 : float, constant potential on the surface of the sphere 1. phi02 : float, constant potential on the surface of the sphere 2. r1 : float, radius of sphere 1. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E_inter: float, interaction energy. """ N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p K2 = special.kv(index2, kappa * r2) K2p = index / (kappa * r2) * K2[0:-1] - K2[1:] k2 = special.kv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) k2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.kv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * K2p I1 = special.iv(index2, kappa * r1) I1p = index / (kappa * r1) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.iv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * I1p I2 = special.iv(index2, kappa * r2) I2p = index / (kappa * r2) * I2[0:-1] + I2[1:] i2 = special.iv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) i2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.iv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * I2p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB M = numpy.zeros((2 * N, 2 * N), float) for j in range(N): for n in range(N): M[j, n + N] = (2 * j + 1) * B[j, n] * i1[j] / k2[n] M[j + N, n] = (2 * j + 1) * B[j, n] * i2[j] / k1[n] if n == j: M[j, n] = 1 M[j + N, n + N] = 1 RHS = numpy.zeros(2 * N) RHS[0] = phi01 RHS[N] = phi02 coeff = linalg.solve(M, RHS) a = coeff[0:N] / k1 b = coeff[N:2 * N] / k2 a0 = a[0] a0_inf = phi01 / k1[0] b0 = b[0] b0_inf = phi02 / k2[0] U1_inf = a0_inf * k1p[0] U1_h = a0 * k1p[0] + i1p[0] * numpy.sum(b * B[:, 0]) U2_inf = b0_inf * k2p[0] U2_h = b0 * k2p[0] + i2p[0] * numpy.sum(a * B[:, 0]) C1 = 2 * pi * kappa * phi01 * r1 * r1 * epsilon C2 = 2 * pi * kappa * phi02 * r2 * r2 * epsilon C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E_inter = C0 * (C1 * (U1_h - U1_inf) + C2 * (U2_h - U2_inf))
return E_inter
[docs]def constant_charge_twosphere_dissimilar(sigma01, sigma02, r1, r2, R, kappa, epsilon): """ It computes the interaction energy between two dissimilar spheres at constant charge, immersed in water. Arguments ---------- sigma01: float, constant charge on the surface of the sphere 1. sigma02: float, constant charge on the surface of the sphere 2. r1 : float, radius of sphere 1. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E_inter: float, interaction energy. """ N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p K2 = special.kv(index2, kappa * r2) K2p = index / (kappa * r2) * K2[0:-1] - K2[1:] k2 = special.kv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) k2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.kv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * K2p I1 = special.iv(index2, kappa * r1) I1p = index / (kappa * r1) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.iv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * I1p I2 = special.iv(index2, kappa * r2) I2p = index / (kappa * r2) * I2[0:-1] + I2[1:] i2 = special.iv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) i2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.iv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * I2p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB M = numpy.zeros((2 * N, 2 * N), float) for j in range(N): for n in range(N): M[j, n + N] = (2 * j + 1) * B[j, n] * r1 * i1p[j] / (r2 * k2p[n]) M[j + N, n] = (2 * j + 1) * B[j, n] * r2 * i2p[j] / (r1 * k1p[n]) if n == j: M[j, n] = 1 M[j + N, n + N] = 1 RHS = numpy.zeros(2 * N) RHS[0] = sigma01 * r1 / epsilon RHS[N] = sigma02 * r2 / epsilon coeff = linalg.solve(M, RHS) a = coeff[0:N] / (-r1 * kappa * k1p) b = coeff[N:2 * N] / (-r2 * kappa * k2p) a0 = a[0] a0_inf = -sigma01 / (epsilon * kappa * k1p[0]) b0 = b[0] b0_inf = -sigma02 / (epsilon * kappa * k2p[0]) U1_inf = a0_inf * k1[0] U1_h = a0 * k1[0] + i1[0] * numpy.sum(b * B[:, 0]) U2_inf = b0_inf * k2[0] U2_h = b0 * k2[0] + i2[0] * numpy.sum(a * B[:, 0]) C1 = 2 * pi * sigma01 * r1 * r1 C2 = 2 * pi * sigma02 * r2 * r2 C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E_inter = C0 * (C1 * (U1_h - U1_inf) + C2 * (U2_h - U2_inf))
return E_inter
[docs]def molecule_constant_potential(q, phi02, r1, r2, R, kappa, E_1, E_2): """ It computes the interaction energy between a molecule (sphere with point-charge in the center) and a sphere at constant potential, immersed in water. Arguments ---------- q : float, number of qe to be asigned to the charge. phi02 : float, constant potential on the surface of the sphere 2. r1 : float, radius of sphere 1, i.e the molecule. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. E_1 : float, dielectric constant inside the sphere/molecule. E_2 : float, dielectric constant outside the sphere/molecule. Returns -------- E_inter: float, interaction energy. """ N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p K2 = special.kv(index2, kappa * r2) K2p = index / (kappa * r2) * K2[0:-1] - K2[1:] k2 = special.kv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) k2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.kv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * K2p I1 = special.iv(index2, kappa * r1) I1p = index / (kappa * r1) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.iv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * I1p I2 = special.iv(index2, kappa * r2) I2p = index / (kappa * r2) * I2[0:-1] + I2[1:] i2 = special.iv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) i2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.iv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * I2p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB E_hat = E_1 / E_2 M = numpy.zeros((2 * N, 2 * N), float) for j in range(N): for n in range(N): M[j, n + N] = (2 * j + 1) * B[j, n] * ( kappa * i1p[j] / k2[n] - E_hat * j / r1 * i1[j] / k2[n]) M[j + N, n] = (2 * j + 1) * B[j, n] * i2[j] * 1 / ( kappa * k1p[n] - E_hat * n / r1 * k1[n]) if n == j: M[j, n] = 1 M[j + N, n + N] = 1 RHS = numpy.zeros(2 * N) RHS[0] = -E_hat * q / (4 * pi * E_1 * r1 * r1) RHS[N] = phi02 coeff = linalg.solve(M, RHS) a = coeff[0:N] / (kappa * k1p - E_hat * numpy.arange(N) / r1 * k1) b = coeff[N:2 * N] / k2 a0 = a[0] a0_inf = -E_hat * q / (4 * pi * E_1 * r1 * r1) * 1 / (kappa * k1p[0]) b0 = b[0] b0_inf = phi02 / k2[0] phi_inf = a0_inf * k1[0] - q / (4 * pi * E_1 * r1) phi_h = a0 * k1[0] + i1[0] * numpy.sum(b * B[:, 0]) - q / (4 * pi * E_1 * r1) phi_inter = phi_h - phi_inf U_inf = b0_inf * k2p[0] U_h = b0 * k2p[0] + i2p[0] * numpy.sum(a * B[:, 0]) U_inter = U_h - U_inf C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) C1 = q * 0.5 C2 = 2 * pi * kappa * phi02 * r2 * r2 * E_2 E_inter = C0 * (C1 * phi_inter + C2 * U_inter)
return E_inter
[docs]def molecule_constant_charge(q, sigma02, r1, r2, R, kappa, E_1, E_2): """ It computes the interaction energy between a molecule (sphere with point-charge in the center) and a sphere at constant charge, immersed in water. Arguments ---------- q : float, number of qe to be asigned to the charge. sigma02: float, constant charge on the surface of the sphere 2. r1 : float, radius of sphere 1, i.e the molecule. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. E_1 : float, dielectric constant inside the sphere/molecule. E_2 : float, dielectric constant outside the sphere/molecule. Returns -------- E_inter: float, interaction energy. """ N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * r1) K1p = index / (kappa * r1) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.kv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * K1p K2 = special.kv(index2, kappa * r2) K2p = index / (kappa * r2) * K2[0:-1] - K2[1:] k2 = special.kv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) k2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.kv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * K2p I1 = special.iv(index2, kappa * r1) I1p = index / (kappa * r1) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r1)**(3 / 2.)) * special.iv( index, kappa * r1) + numpy.sqrt(pi / (2 * kappa * r1)) * I1p I2 = special.iv(index2, kappa * r2) I2p = index / (kappa * r2) * I2[0:-1] + I2[1:] i2 = special.iv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) i2p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * r2)**(3 / 2.)) * special.iv( index, kappa * r2) + numpy.sqrt(pi / (2 * kappa * r2)) * I2p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB E_hat = E_1 / E_2 M = numpy.zeros((2 * N, 2 * N), float) for j in range(N): for n in range(N): M[j, n + N] = (2 * j + 1) * B[j, n] * ( i1p[j] / k2p[n] - E_hat * j / r1 * i1[j] / (kappa * k2p[n])) M[j + N, n] = (2 * j + 1) * B[j, n] * i2p[j] * kappa * 1 / ( kappa * k1p[n] - E_hat * n / r1 * k1[n]) if n == j: M[j, n] = 1 M[j + N, n + N] = 1 RHS = numpy.zeros(2 * N) RHS[0] = -E_hat * q / (4 * pi * E_1 * r1 * r1) RHS[N] = -sigma02 / E_2 coeff = linalg.solve(M, RHS) a = coeff[0:N] / (kappa * k1p - E_hat * numpy.arange(N) / r1 * k1) b = coeff[N:2 * N] / (kappa * k2p) a0 = a[0] a0_inf = -E_hat * q / (4 * pi * E_1 * r1 * r1) * 1 / (kappa * k1p[0]) b0 = b[0] b0_inf = -sigma02 / (E_2 * kappa * k2p[0]) phi_inf = a0_inf * k1[0] - q / (4 * pi * E_1 * r1) phi_h = a0 * k1[0] + i1[0] * numpy.sum(b * B[:, 0]) - q / (4 * pi * E_1 * r1) phi_inter = phi_h - phi_inf U_inf = b0_inf * k2[0] U_h = b0 * k2[0] + i2[0] * numpy.sum(a * B[:, 0]) U_inter = U_h - U_inf C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) C1 = q * 0.5 C2 = 2 * pi * sigma02 * r2 * r2 E_inter = C0 * (C1 * phi_inter + C2 * U_inter)
return E_inter
[docs]def constant_potential_twosphere_identical(phi01, phi02, r1, r2, R, kappa, epsilon): """ It computes the interaction energy for two spheres at constants surface potential, according to Carnie&Chan-1993. Arguments ---------- phi01 : float, constant potential on the surface of the sphere 1. phi02 : float, constant potential on the surface of the sphere 2. r1 : float, radius of sphere 1. r2 : float, radius of sphere 2. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Note: Even though it admits phi01 and phi02, they should be identical; and the same is applicable to r1 and r2. Returns -------- E_inter: float, interaction energy. """ # From Carnie+Chan 1993 N = 20 # Number of terms in expansion qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index = numpy.arange(N, dtype=float) + 0.5 k1 = special.kv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) k2 = special.kv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) i1 = special.iv(index, kappa * r1) * numpy.sqrt(pi / (2 * kappa * r1)) i2 = special.iv(index, kappa * r2) * numpy.sqrt(pi / (2 * kappa * r2)) B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB M = numpy.zeros((N, N), float) for i in range(N): for j in range(N): M[i, j] = (2 * i + 1) * B[i, j] * i1[i] if i == j: M[i, j] += k1[i] RHS = numpy.zeros(N) RHS[0] = phi01 a = linalg.solve(M, RHS) a0 = a[0] U = 4 * pi * (-pi / 2 * a0 / phi01 * 1 / numpy.sinh(kappa * r1) + kappa * r1 + kappa * r1 / numpy.tanh(kappa * r1)) C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) C1 = r1 * epsilon * phi01 * phi01 E_inter = U * C1 * C0
return E_inter
[docs]def constant_charge_twosphere_identical(sigma, a, R, kappa, epsilon): """ It computes the interaction energy for two spheres at constants surface charge, according to Carnie&Chan-1993. Arguments ---------- sigma : float, constant charge on the surface of the spheres. a : float, radius of spheres. R : float, distance center to center. kappa : float, reciprocal of Debye length. epsilon: float, water dielectric constant. Returns -------- E_inter: float, interaction energy. """ # From Carnie+Chan 1993 N = 10 # Number of terms in expansion E_p = 0 # Permitivitty inside sphere qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 index2 = numpy.arange(N + 1, dtype=float) + 0.5 index = index2[0:-1] K1 = special.kv(index2, kappa * a) K1p = index / (kappa * a) * K1[0:-1] - K1[1:] k1 = special.kv(index, kappa * a) * numpy.sqrt(pi / (2 * kappa * a)) k1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * a)**(3 / 2.)) * special.kv( index, kappa * a) + numpy.sqrt(pi / (2 * kappa * a)) * K1p I1 = special.iv(index2, kappa * a) I1p = index / (kappa * a) * I1[0:-1] + I1[1:] i1 = special.iv(index, kappa * a) * numpy.sqrt(pi / (2 * kappa * a)) i1p = -numpy.sqrt(pi / 2) * 1 / (2 * (kappa * a)**(3 / 2.)) * special.iv( index, kappa * a) + numpy.sqrt(pi / (2 * kappa * a)) * I1p B = numpy.zeros((N, N), dtype=float) for n in range(N): for m in range(N): for nu in range(N): if n >= nu and m >= nu: g1 = gamma(n - nu + 0.5) g2 = gamma(m - nu + 0.5) g3 = gamma(nu + 0.5) g4 = gamma(m + n - nu + 1.5) f1 = factorial(n + m - nu) f2 = factorial(n - nu) f3 = factorial(m - nu) f4 = factorial(nu) Anm = g1 * g2 * g3 * f1 * (n + m - 2 * nu + 0.5) / ( pi * g4 * f2 * f3 * f4) kB = special.kv(n + m - 2 * nu + 0.5, kappa * R) * numpy.sqrt(pi / (2 * kappa * R)) B[n, m] += Anm * kB M = numpy.zeros((N, N), float) for i in range(N): for j in range(N): M[i, j] = (2 * i + 1) * B[i, j] * ( E_p / epsilon * i * i1[i] - a * kappa * i1p[i]) if i == j: M[i, j] += (E_p / epsilon * i * k1[i] - a * kappa * k1p[i]) RHS = numpy.zeros(N) RHS[0] = a * sigma / epsilon a_coeff = linalg.solve(M, RHS) a0 = a_coeff[0] C0 = a * sigma / epsilon CC0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J * E_0) E_inter = 4 * pi * a * epsilon * C0 * C0 * CC0(pi * a0 / (2 * C0 * ( kappa * a * numpy.cosh(kappa * a) - numpy.sinh(kappa * a))) - 1 / ( 1 + kappa * a) - 1 / (kappa * a * 1 / numpy.tanh(kappa * a) - 1))
return E_inter
[docs]def Cext_analytical(radius, wavelength, diel_out, diel_in): """ Calculates the analytical solution of the extinction cross section. This solution is valid when the nano particle involved is a sphere. Arguments ---------- radius : float, radius of the sphere in [nm]. wavelength: float/array of floats, wavelength of the incident electric field in [nm]. diel_out : complex/array of complex, dielectric constant inside surface. diel_in : complex/array of complex, dielectric constant inside surface. Returns -------- Cext_an : float/array of floats, extinction cross section. """ wavenumber = 2 * numpy.pi * numpy.sqrt(diel_out) / wavelength C1 = wavenumber**2 * (diel_in / diel_out - 1) / (diel_in / diel_out + 2) Cext_an = 4 * numpy.pi * radius**3 / wavenumber.real * C1.imag
return Cext_an