/* Test permutation symmetries over variables and modes etc. */ void consistency_test(void) { xc_functional fun = xc_new_functional(); double d_unpolarized[8] = {1,1, 2,-3,4, 2,-3,4}; double d_pol_a[8] = {1,2.1, 2,-3,4, 7,-8,9}; double d_pol_b[8] = {2.1,1, 7,-8,9, 2,-3,4}; int nout; double *output; double *out2; xc_set(fun,"pbe",1.0); xc_eval_setup(fun,XC_A_B_AX_AY_AZ_BX_BY_BZ,XC_PARTIAL_DERIVATIVES,1); nout = xc_output_length(fun); check("correct output length 1",nout == 9); // 1 + 8 output = malloc(sizeof(*output)*nout); out2 = malloc(sizeof(*output)*nout); xc_eval(fun,d_unpolarized,output); checknum("unpolarized symmetry 1",output[1] - output[2],0,1e-14,1e-12); checknum("unpolarized symmetry 2",output[3] - output[6],0,1e-14,1e-12); checknum("unpolarized symmetry 3",output[4] - output[7],0,1e-14,1e-12); checknum("unpolarized symmetry 4",output[5] - output[8],0,1e-14,1e-12); xc_eval(fun,d_pol_a,output); xc_eval(fun,d_pol_b,out2); checknum("polarized symmetry 1",output[1] - out2[2],0,1e-14,1e-12); checknum("polarized symmetry 2",output[3] - out2[6],0,1e-14,1e-12); checknum("polarized symmetry 3",output[4] - out2[7],0,1e-14,1e-12); checknum("polarized symmetry 4",output[5] - out2[8],0,1e-14,1e-12); checknum("polarized symmetry 5",out2[1] - output[2],0,1e-14,1e-12); checknum("polarized symmetry 6",out2[3] - output[6],0,1e-14,1e-12); checknum("polarized symmetry 7",out2[4] - output[7],0,1e-14,1e-12); checknum("polarized symmetry 8",out2[5] - output[8],0,1e-14,1e-12); free(output); free(out2); xc_free_functional(fun); }
// Test that gradient square norma and gradient elements modes are consistent void gradient_forms_test(void) { xc_functional fun = xc_new_functional(); double d_elements[8] = {1, 2.1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6}; double d_sqnorm[5] = {d_elements[0],d_elements[1]}; int nout,i; double *output; double *out2; xc_set(fun,"blyp",1.0); xc_eval_setup(fun,XC_A_B_AX_AY_AZ_BX_BY_BZ,XC_PARTIAL_DERIVATIVES,1); nout = xc_output_length(fun); check("correct output length 1",nout == 9); // 1 + 8 output = malloc(sizeof(*output)*nout); xc_eval(fun,d_elements,output); xc_eval_setup(fun,XC_A_B_GAA_GAB_GBB, XC_PARTIAL_DERIVATIVES,1); nout = xc_output_length(fun); check("correct output length 1",nout == 6); // 1 + 5 out2 = malloc(sizeof(*out2)*nout); d_sqnorm[2] = d_elements[2]*d_elements[2] + d_elements[3]*d_elements[3] + d_elements[4]*d_elements[4]; d_sqnorm[3] = d_elements[2]*d_elements[5] + d_elements[3]*d_elements[6] + d_elements[4]*d_elements[7]; d_sqnorm[4] = d_elements[5]*d_elements[5] + d_elements[6]*d_elements[6] + d_elements[7]*d_elements[7]; xc_eval(fun,d_sqnorm,out2); checknum("Grad modes energy",output[0] - out2[0],0,1e-14,1e-12); checknum("Grad modes density derivs alpha",output[1] - out2[1],0,1e-14,1e-12); checknum("Grad modes density derivs beta", output[2] - out2[2],0,1e-14,1e-12); // d/dg_ax = d/dgaa * g_ax + d/dgab * g_bx for (i=0;i<3;i++) { checknum("Grad modes density grad alpha",output[3+i] - (2*out2[3]*d_elements[2+i] + out2[4]*d_elements[5+i]) ,0,1e-14,1e-12); checknum("Grad modes density grad beta",output[6+i] - (2*out2[5]*d_elements[5+i] + out2[4]*d_elements[2+i]) ,0,1e-14,1e-12); } free(output); free(out2); xc_free_functional(fun); }
// Compute the xc potential(s). This is simple for lda and more complicated for // GGA's. For metaGAA's that depend on tau this is a non-local problem and // cannot be solved by xcfun. Laplacian dependent metaGGA's could be implemented.. // Another option is to evaluate the divergence directly in cartesian coordinates, // but one have to find a way to do this without introducing the gradient components // explicitly (for niceness) void xc_potential(xc_functional fun, const double *density, double *e_xc, double *v_xc) { if (fun->mode == XC_VARS_AB) { if (fun->type == XC_LDA) { double out[3]; xc_eval(fun,1,density,out); e_xc[0] = out[0]; v_xc[0] = out[1]; v_xc[1] = out[2]; } // Expecting lap_a and lap_b as element 5 and 6 of density // Using that v_xc = dE/dn - div dE/dgradn // When deriving the expressions it helps to have the operator // (g_a).nabla act on the basic variables (and the same for g_b). else if (fun->type == XC_GGA) { const int gaa = 2, gab = 3, gbb = 4, lapa = 5, lapb = 6; double out[21]; xc_eval(fun,2,density,out); e_xc[0] = out[XC_D00000]; v_xc[0] = out[XC_D10000]; v_xc[0] -= 2*density[lapa]*out[XC_D00100] + density[lapb]*out[XC_D00010]; v_xc[0] -= 2*(out[XC_D10100]*density[gaa] + out[XC_D01100]*density[gab] + out[XC_D00200]*(2*density[lapa]*density[gaa]) + out[XC_D00110]*(density[lapa]*density[gab] + density[lapb]*density[gaa]) + out[XC_D00101]*(2*density[lapb]*density[gab]) ); v_xc[0] -= (out[XC_D10010]*density[gab] + out[XC_D01010]*density[gbb] + out[XC_D00110]*(2*density[lapa]*density[gab]) + out[XC_D00020]*(density[lapb]*density[gab] + density[lapa]*density[gbb]) + out[XC_D00011]*(2*density[lapb]*density[gbb])); v_xc[1] = out[XC_D01000]; v_xc[1] -= 2*density[lapb]*out[XC_D00001] + density[lapa]*out[XC_D00010]; v_xc[1] -= 2*(out[XC_D01001]*density[gbb] + out[XC_D10001]*density[gab] + out[XC_D00002]*(2*density[lapb]*density[gbb]) + out[XC_D00011]*(density[lapb]*density[gab] + density[lapa]*density[gbb]) + out[XC_D00101]*(2*density[lapa]*density[gab]) ); v_xc[1] -= (out[XC_D01010]*density[gab] + out[XC_D10010]*density[gaa] + out[XC_D00011]*(2*density[lapb]*density[gab]) + out[XC_D00020]*(density[lapa]*density[gab] + density[lapb]*density[gaa]) + out[XC_D00110]*(2*density[lapa]*density[gaa])); } else { xcint_die("xc_potential() not implemented for metaGGA's",fun->type); } } else if (fun->mode == XC_VARS_N) { if (fun->type == XC_LDA) { double out[2]; xc_eval(fun,1,density,out); e_xc[0] = out[0]; v_xc[0] = out[1]; } else { xcint_die("xc_potential() GGA not implemented for XC_VARS_N", fun->type); } } else { xcint_die("xc_potential() GGA only implemented for AB mode", fun->mode); } }