def test_libxc_gga_value(): # compare the calculated value of GGA potential dtype = torch.float64 xc = get_libxc("gga_x_pbe") assert xc.family == 2 assert xc.family == 2 torch.manual_seed(123) n = 100 rho_u = torch.rand((n, ), dtype=dtype) rho_d = torch.rand((n, ), dtype=dtype) rho_tot = rho_u + rho_d gradn_u = torch.rand((n, 3), dtype=dtype) * 0 gradn_d = torch.rand((n, 3), dtype=dtype) * 0 gradn_tot = gradn_u + gradn_d densinfo_u = ValGrad(value=rho_u, grad=gradn_u) densinfo_d = ValGrad(value=rho_d, grad=gradn_d) densinfo_tot = densinfo_u + densinfo_d densinfo = SpinParam(u=densinfo_u, d=densinfo_d) # calculate the energy and compare with analytical expression edens_unpol = xc.get_edensityxc(densinfo_tot) edens_unpol_true = pbe_e_true(rho_tot, gradn_tot) assert torch.allclose(edens_unpol, edens_unpol_true) edens_pol = xc.get_edensityxc(densinfo) edens_pol_true = 0.5 * (pbe_e_true(2 * rho_u, 2 * gradn_u) + pbe_e_true(2 * rho_d, 2 * gradn_d)) assert torch.allclose(edens_pol, edens_pol_true)
def test_libxc_lda_value(): # check if the value is consistent xc = get_libxc("lda_x") assert xc.family == 1 assert xc.family == 1 torch.manual_seed(123) n = 100 rho_u = torch.rand((n, ), dtype=torch.float64) rho_d = torch.rand((n, ), dtype=torch.float64) rho_tot = rho_u + rho_d densinfo_u = ValGrad(value=rho_u) densinfo_d = ValGrad(value=rho_d) densinfo = SpinParam(u=densinfo_u, d=densinfo_d) densinfo_tot = ValGrad(value=rho_tot) # calculate the energy and compare with analytic edens_unpol = xc.get_edensityxc(densinfo_tot) edens_unpol_true = lda_e_true(rho_tot) assert torch.allclose(edens_unpol, edens_unpol_true) edens_pol = xc.get_edensityxc(densinfo) edens_pol_true = 0.5 * (lda_e_true(2 * rho_u) + lda_e_true(2 * rho_d)) assert torch.allclose(edens_pol, edens_pol_true) vxc_unpol = xc.get_vxc(densinfo_tot) vxc_unpol_value_true = lda_v_true(rho_tot) assert torch.allclose(vxc_unpol.value, vxc_unpol_value_true) vxc_pol = xc.get_vxc(densinfo) vxc_pol_u_value_true = lda_v_true(2 * rho_u) vxc_pol_d_value_true = lda_v_true(2 * rho_d) assert torch.allclose(vxc_pol.u.value, vxc_pol_u_value_true) assert torch.allclose(vxc_pol.d.value, vxc_pol_d_value_true)
def test_libxc_ldac_value(): # check if the value of lda_c_pw is consistent xc = get_libxc("lda_c_pw") assert xc.family == 1 assert xc.family == 1 torch.manual_seed(123) n = 100 rho_1 = torch.rand((n,), dtype=torch.float64) rho_2 = torch.rand((n,), dtype=torch.float64) rho_u = torch.maximum(rho_1, rho_2) rho_d = torch.minimum(rho_1, rho_2) rho_tot = rho_u + rho_d xi = (rho_u - rho_d) / rho_tot densinfo_u = ValGrad(value=rho_u) densinfo_d = ValGrad(value=rho_d) densinfo = SpinParam(u=densinfo_u, d=densinfo_d) densinfo_tot = ValGrad(value=rho_tot) # calculate the energy and compare with analytic edens_unpol = xc.get_edensityxc(densinfo_tot) edens_unpol_true = ldac_e_true(rho_tot, rho_tot * 0) assert torch.allclose(edens_unpol, edens_unpol_true) edens_pol = xc.get_edensityxc(densinfo) edens_pol_true = ldac_e_true(rho_tot, xi) assert torch.allclose(edens_pol, edens_pol_true)
def test_xc_default_vxc(xccls, libxcname): # test if the default vxc implementation is correct, compared to libxc dtype = torch.float64 xc = xccls() libxc = get_libxc(libxcname) torch.manual_seed(123) n = 100 rho_u = torch.rand((n, ), dtype=dtype) rho_d = torch.rand((n, ), dtype=dtype) rho_tot = rho_u + rho_d gradn_u = torch.rand((n, 3), dtype=dtype) * 0 gradn_d = torch.rand((n, 3), dtype=dtype) * 0 gradn_tot = gradn_u + gradn_d densinfo_u = ValGrad(value=rho_u, grad=gradn_u) densinfo_d = ValGrad(value=rho_d, grad=gradn_d) densinfo_tot = densinfo_u + densinfo_d densinfo = SpinParam(u=densinfo_u, d=densinfo_d) def assert_valgrad(vg1, vg2): assert torch.allclose(vg1.value, vg2.value) assert (vg1.grad is None) == (vg2.grad is None) assert (vg1.lapl is None) == (vg2.lapl is None) if vg1.grad is not None: assert torch.allclose(vg1.grad, vg2.grad) if vg1.lapl is not None: assert torch.allclose(vg1.lapl, vg2.lapl) # check if the energy is the same (implementation check) xc_edens_unpol = xc.get_edensityxc(densinfo_tot) lxc_edens_unpol = libxc.get_edensityxc(densinfo_tot) assert torch.allclose(xc_edens_unpol, lxc_edens_unpol) xc_edens_pol = xc.get_edensityxc(densinfo) lxc_edens_pol = libxc.get_edensityxc(densinfo) assert torch.allclose(xc_edens_pol, lxc_edens_pol) # calculate the potential and compare with analytical expression xcpotinfo_unpol = xc.get_vxc(densinfo_tot) lxcpotinfo_unpol = libxc.get_vxc(densinfo_tot) assert_valgrad(xcpotinfo_unpol, lxcpotinfo_unpol) xcpotinfo_pol = xc.get_vxc(densinfo) lxcpotinfo_pol = libxc.get_vxc(densinfo) # print(type(xcpotinfo_pol), type(lxcpotinfo_unpol)) assert_valgrad(xcpotinfo_pol.u, lxcpotinfo_pol.u) assert_valgrad(xcpotinfo_pol.d, lxcpotinfo_pol.d)
def test_libxc_mgga_gradcheck(): name = "mgga_x_scan" xc = get_libxc(name) torch.manual_seed(123) n = 2 rho_u = torch.rand((n,), dtype=torch.float64).requires_grad_() rho_d = torch.rand((n,), dtype=torch.float64).requires_grad_() grad_u = torch.rand((3, n), dtype=torch.float64).requires_grad_() grad_d = torch.rand((3, n), dtype=torch.float64).requires_grad_() lapl_u = torch.rand((n,), dtype=torch.float64).requires_grad_() lapl_d = torch.rand((n,), dtype=torch.float64).requires_grad_() tau_w_u = (torch.norm(grad_u, dim=-2) ** 2 / (8 * rho_u)).detach() tau_w_d = (torch.norm(grad_d, dim=-2) ** 2 / (8 * rho_d)).detach() kin_u = (torch.rand((n,), dtype=torch.float64) + tau_w_u).requires_grad_() kin_d = (torch.rand((n,), dtype=torch.float64) + tau_w_d).requires_grad_() def get_edens_unpol(xc, rho, grad, lapl, kin): densinfo = ValGrad(value=rho, grad=grad, lapl=lapl, kin=kin) return xc.get_edensityxc(densinfo) def get_vxc_unpol(xc, rho, grad, lapl, kin): densinfo = ValGrad(value=rho, grad=grad, lapl=lapl, kin=kin) return xc.get_vxc(densinfo).value def get_edens_pol(xc, rho_u, rho_d, grad_u, grad_d, lapl_u, lapl_d, kin_u, kin_d): densinfo_u = ValGrad(value=rho_u, grad=grad_u, lapl=lapl_u, kin=kin_u) densinfo_d = ValGrad(value=rho_d, grad=grad_d, lapl=lapl_d, kin=kin_d) return xc.get_edensityxc(SpinParam(u=densinfo_u, d=densinfo_d)) def get_vxc_pol(xc, rho_u, rho_d, grad_u, grad_d, lapl_u, lapl_d, kin_u, kin_d): densinfo_u = ValGrad(value=rho_u, grad=grad_u, lapl=lapl_u, kin=kin_u) densinfo_d = ValGrad(value=rho_d, grad=grad_d, lapl=lapl_d, kin=kin_d) vxc = xc.get_vxc(SpinParam(u=densinfo_u, d=densinfo_d)) return vxc.u.value, vxc.d.value param_unpol = (xc, rho_u, grad_u, lapl_u, kin_u) param_pol = (xc, rho_u, rho_d, grad_u, grad_d, lapl_u, lapl_d, kin_u, kin_d) torch.autograd.gradcheck(get_edens_unpol, param_unpol) torch.autograd.gradcheck(get_vxc_unpol, param_unpol) torch.autograd.gradgradcheck(get_edens_unpol, param_unpol) torch.autograd.gradgradcheck(get_vxc_unpol, param_unpol) torch.autograd.gradcheck(get_edens_pol, param_pol) torch.autograd.gradcheck(get_vxc_pol, param_pol) torch.autograd.gradgradcheck(get_edens_pol, param_pol) torch.autograd.gradgradcheck(get_vxc_pol, param_pol)
def test_libxc_gga_gradcheck(): name = "gga_x_pbe" xc = get_libxc(name) torch.manual_seed(123) n = 2 rho_u = torch.rand((n, ), dtype=torch.float64).requires_grad_() rho_d = torch.rand((n, ), dtype=torch.float64).requires_grad_() grad_u = torch.rand((n, 3), dtype=torch.float64).requires_grad_() grad_d = torch.rand((n, 3), dtype=torch.float64).requires_grad_() def get_edens_unpol(xc, rho, grad): densinfo = ValGrad(value=rho, grad=grad) return xc.get_edensityxc(densinfo) def get_vxc_unpol(xc, rho, grad): densinfo = ValGrad(value=rho, grad=grad) return xc.get_vxc(densinfo).value def get_edens_pol(xc, rho_u, rho_d, grad_u, grad_d): densinfo_u = ValGrad(value=rho_u, grad=grad_u) densinfo_d = ValGrad(value=rho_d, grad=grad_d) return xc.get_edensityxc(SpinParam(u=densinfo_u, d=densinfo_d)) def get_vxc_pol(xc, rho_u, rho_d, grad_u, grad_d): densinfo_u = ValGrad(value=rho_u, grad=grad_u) densinfo_d = ValGrad(value=rho_d, grad=grad_d) vxc = xc.get_vxc(SpinParam(u=densinfo_u, d=densinfo_d)) return vxc.u.value, vxc.d.value param_unpol = (xc, rho_u, grad_u) param_pol = (xc, rho_u, rho_d, grad_u, grad_d) torch.autograd.gradcheck(get_edens_unpol, param_unpol) torch.autograd.gradcheck(get_vxc_unpol, param_unpol) torch.autograd.gradgradcheck(get_edens_unpol, param_unpol) torch.autograd.gradgradcheck(get_vxc_unpol, param_unpol) torch.autograd.gradcheck(get_edens_pol, param_pol) torch.autograd.gradcheck(get_vxc_pol, param_pol) torch.autograd.gradgradcheck(get_edens_pol, param_pol) torch.autograd.gradgradcheck(get_vxc_pol, param_pol)
def test_libxc_mgga_value(): # compare the calculated value of MGGA potential dtype = torch.float64 xc = get_libxc("mgga_x_scan") assert xc.family == 4 torch.manual_seed(123) n = 100 rho_u = torch.rand((n,), dtype=dtype) rho_d = torch.rand((n,), dtype=dtype) rho_tot = rho_u + rho_d gradn_u = torch.rand((3, n), dtype=dtype) * 0 gradn_d = torch.rand((3, n), dtype=dtype) * 0 gradn_tot = gradn_u + gradn_d lapl_u = torch.rand((n,), dtype=torch.float64) lapl_d = torch.rand((n,), dtype=torch.float64) lapl_tot = lapl_u + lapl_d tau_w_u = (torch.norm(gradn_u, dim=-2) ** 2 / (8 * rho_u)) tau_w_d = (torch.norm(gradn_d, dim=-2) ** 2 / (8 * rho_d)) kin_u = torch.rand((n,), dtype=torch.float64) + tau_w_u kin_d = torch.rand((n,), dtype=torch.float64) + tau_w_d kin_tot = kin_u + kin_d densinfo_u = ValGrad(value=rho_u, grad=gradn_u, lapl=lapl_u, kin=kin_u) densinfo_d = ValGrad(value=rho_d, grad=gradn_d, lapl=lapl_d, kin=kin_d) densinfo_tot = densinfo_u + densinfo_d densinfo = SpinParam(u=densinfo_u, d=densinfo_d) # calculate the energy and compare with analytical expression edens_unpol = xc.get_edensityxc(densinfo_tot) edens_unpol_true = scan_e_true(rho_tot, gradn_tot, lapl_tot, kin_tot) assert torch.allclose(edens_unpol, edens_unpol_true) edens_pol = xc.get_edensityxc(densinfo) edens_pol_true = 0.5 * (scan_e_true(2 * rho_u, 2 * gradn_u, 2 * lapl_u, 2 * kin_u) + \ scan_e_true(2 * rho_d, 2 * gradn_d, 2 * lapl_d, 2 * kin_d)) assert torch.allclose(edens_pol, edens_pol_true)