示例#1
0
    def __init__(self, r_s, N, N_k, kappa_scale):
        """
        jellium in a cubic cell, unpolarized
        
        r_s is the usual usual length scale
        N is the number of up electrons
        i.e. the total number of electrons is 2N
        and N should be chosen for a closed shell

        N_k (indirectly) sets the number of kvectors to be kept
        and used for ewald sums
        kappa_scale (indirectly) sets the smearing parameter
        for ewald sums: kappa = kappa_scale / L
        should always be tested for convergence

        everything begins uninitialized
        """
        self.L = 1.612*r_s*((2*N)**(1./3))
        self.electron = pbc.electron(N, N)
        v = self.L*np.eye(3)
        self.supercell = pbc.cell(v[0], v[1], v[2])
        self.slater_up = np.zeros((N, N))
        self.slater_dn = np.zeros((N, N))
        self.inverse_up = np.zeros_like(self.slater_up)
        self.inverse_dn = np.zeros_like(self.slater_dn)
        #ewald tables, called u
        self.u_sr_uu = np.zeros_like(self.electron.uu_table)
        self.u_sr_dd = np.zeros_like(self.electron.dd_table)
        self.u_sr_ud = np.zeros_like(self.electron.ud_table)
        self.u_lr_uu = np.zeros_like(self.u_sr_uu)
        self.u_lr_dd = np.zeros_like(self.u_sr_dd)
        self.u_lr_ud = np.zeros_like(self.u_sr_ud)
        #parameters and additional tables for jastrow
        n = 2*N/self.supercell.volume #number density, for RPA
        self.A = 1/np.sqrt(4*np.pi*n)
        self.F_uu = np.sqrt(2*self.A)
        self.F_ud = np.sqrt(self.A)
        self.u_exp_uu = np.zeros_like(self.electron.uu_table)
        self.u_exp_dd = np.zeros_like(self.electron.dd_table)
        self.u_exp_ud = np.zeros_like(self.electron.ud_table)
        self.N = N
        self.k = self.supercell.kvecs(N_k)[:,:3]
        self.kappa = kappa_scale / self.L
示例#2
0
def test_is_greater_than():
    """
    the whole reason is_greater_than() exists in the first place
    is that, in pbc.cell.kvecs(), the sorting results were machine
    dependent, presumably because the behavior of (a>b) when a and b
    are supposed to be equal is unpredictable (?). hence this test
    directly targets pbc.cell.kvecs() by comparing its output to
    one generated on a particular machine. at the time of writing,
    the machine is my 2020 macbook air
    """
    #generate list of k
    from pytools.pbc import cell
    v = np.sqrt(2) * np.eye(3)
    supercell = cell(v[0], v[1], v[2])
    klist1 = supercell.kvecs(3)[:, :3]
    with open('data/klist.dat', 'r') as f:
        klist2 = np.loadtxt(f)
    msg = 'pbc.cell.kvecs() did not match test data'
    assert np.allclose(klist1, klist2), msg
示例#3
0
def test_ewald_madelung():
    """
    test ewald sum to see if it can get madelung const for CsCl
    using a 3x3x3 supercell
    the charges are created with the electron class,
    where up and down refer to opposite charges
    """
    alpha = 1.7627 #desired answer
    L = 4.12*3 #4.12 is the lattice const for CsCl
    charge = pbc.electron(27, 27)
    #make structure
    count = 0
    for x in range(3):
        for y in range(3):
            for z in range(3):
                charge.up[count] = [x/3, y/3, z/3]
                count += 1
    charge.dn = np.copy(charge.up) + 1/6
    charge.update_displacement()
    #construct k vectors to sum over
    v = L*np.eye(3)
    supercell = pbc.cell(v[0], v[1], v[2])
    k = supercell.kvecs(4)[1:,:3]
    k *= 2*np.pi/L
    kappa = 6/L #convergence is around here
    #begin ewald sums
    vol = supercell.volume
    ppterm = pbc.ewald(charge.uu_table*L, kappa, k, vol,\
            one_species=True)
    mmterm = pbc.ewald(charge.dd_table*L, kappa, k, vol,\
            one_species=True)
    pmterm = pbc.ewald(charge.ud_table*L, kappa, k, vol,\
            one_species=False)
    self_term = 54*kappa/np.sqrt(np.pi)
    energy = ppterm + mmterm - pmterm - self_term
    #compute madelung constant
    r = L*np.min(np.linalg.norm(charge.ud_table, axis=-1))
    madelung = -energy*r/27
    assert isclose(madelung, alpha, abs_tol=0.0001), \
            'ewald failed to compute madelung constant for CsCl'
示例#4
0
def test_ewald_lr():
    """
    test ewald_lr, which performs the sum over k with matmul
    against a manual sum over k
    """
    #make supercell
    L = 5*np.random.rand()
    v = L*np.eye(3)
    supercell = pbc.cell(v[0], v[1], v[2])
    volume = supercell.volume
    kvecs = supercell.kvecs(3)[1:,:3]
    kvecs *= 2*np.pi/L
    kappa = 5/L
    r = L*np.random.rand(17, 3)
    u = np.zeros(17)
    for n in range(17):
        for k in kvecs:
            ksq = np.dot(k, k)
            kr = np.dot(k, r[n])
            u[n] += np.cos(kr)*np.exp(-ksq / (4*kappa**2)) / ksq
    u *= 4*np.pi/volume
    assert np.isclose(pbc.ewald_lr(r, kappa, kvecs, volume), u).all()
示例#5
0
def test_laplacian_ewald_lr():
    L = 5*np.random.rand()
    v = L*np.eye(3)
    supercell = pbc.cell(v[0], v[1], v[2])
    volume = supercell.volume
    kvecs = supercell.kvecs(3)[1:,:3]
    kvecs *= 2*np.pi/L
    kappa = 5/L
    r = L*np.random.rand(3)
    #compute derivatives
    f = pbc.ewald_lr(r, kappa, kvecs, volume) #h = 0
    h = 0.00001 #finite difference step
    lap = 0
    for i in range(3):
        r[i] += h
        f_fwd = pbc.ewald_lr(r, kappa, kvecs, volume)
        r[i] -= 2*h
        f_bwd = pbc.ewald_lr(r, kappa, kvecs, volume)
        r[i] += h #restore original r
        lap += (f_fwd + f_bwd - 2*f) / h**2
    assert np.isclose(lap, pbc.laplacian_ewald_lr(r, kappa, kvecs, volume),\
            rtol=1e-2)
示例#6
0
def test_grad_ewald_lr():
    L = 5*np.random.rand()
    v = L*np.eye(3)
    supercell = pbc.cell(v[0], v[1], v[2])
    volume = supercell.volume
    kvecs = supercell.kvecs(3)[1:,:3]
    kvecs *= 2*np.pi/L
    kappa = 5/L
    r = L*np.random.rand(3)
    #compute derivatives
    f = pbc.ewald_lr(r, kappa, kvecs, volume) #h = 0
    h = 0.00001 #finite difference step
    grad = np.zeros(3)
    for i in range(3):
        r[i] += h
        fwd = pbc.ewald_lr(r, kappa, kvecs, volume)
        r[i] -= 2*h
        bwd = pbc.ewald_lr(r, kappa, kvecs, volume)
        r[i] += h
        grad[i] = (fwd - bwd) / (2*h)
    assert np.isclose(grad, pbc.grad_ewald_lr(r, kappa, kvecs, volume),\
            rtol=1e-2).all()
示例#7
0
def test_coulomb_potential():
    #this test also relies on electron and cell classes
    from pytools.pbc import electron, cell
    elec = electron(17, 19)
    elec.start_random()
    v = 6.9 * np.eye(3)  #cubic cell, length 6.9
    geometry = cell(v[0], v[1], v[2])
    up_displacement = geometry.crystal_to_cart(elec.uu_table)
    down_displacement = geometry.crystal_to_cart(elec.dd_table)
    updown_displacement = geometry.crystal_to_cart(elec.ud_table)
    #begin computing potentials
    up_potential = pm.coulomb_potential(up_displacement)
    down_potential = pm.coulomb_potential(down_displacement)
    updown_potential = pm.coulomb_potential(updown_displacement, False)
    #computation using loops
    up_manual = 0
    down_manual = 0
    updown_manual = 0
    r_up = np.linalg.norm(up_displacement, axis=-1)
    r_down = np.linalg.norm(down_displacement, axis=-1)
    r_updown = np.linalg.norm(updown_displacement, axis=-1)
    for i in range(elec.N_up):
        for j in range(i):
            up_manual += 1. / r_up[i, j]
    for i in range(elec.N_dn):
        for j in range(i):
            down_manual += 1. / r_down[i, j]
    for i in range(elec.N_up):
        for j in range(elec.N_dn):
            updown_manual += 1. / r_updown[i, j]
    assert isclose(up_potential, up_manual), \
            'coulomb_potential failed for up electrons'
    assert isclose(down_potential, down_manual), \
            'coulomb_potential failed for down electrons'
    assert isclose(updown_potential, updown_manual), \
            'coulomb_potential failed for up-down electrons'