void second_derivatives(xc_func_type *func, double point[5], double der[5][5]) { int i; for(i=0; i<5; i++){ first_derivative(func, point, der[i], i+1); } }
/*! * Off-site contribution to the force constant matrix, i.e. the * 3*n_atoms x 3*n_atoms matrix D_ij for i != j. */ void FCLJCut::offsite(const CrystalSurface *surf, const CrystalSurface::lattice_neighbor_t *pair, int ab, double *_D, Error *error) { int itype = surf->get_type(pair->indexi); int jtype = surf->get_type(pair->indexj); vec<double, 3> e(pair->r); e /= e.nrm2(); mat<double> D(3, _D); outer(e, e, D); mat<double> perp = identity<double>(3) - D; double k = second_derivative(itype, jtype, pair->rnorm); double kappa = first_derivative(itype, jtype, pair->rnorm)/pair->rnorm; D *= -k; perp *= kappa; D -= perp; }
/*! * Dump generic text info to file */ void FCLJCut::dump_info(FILE *f, CrystalSurface *surf, Error *error) { ForceConstants::dump_info(f, surf, error); int nat = surf->get_number_of_atoms(); fprintf(f, "Force constants for each neighbor shell:\n"); for (int i = 0; i < nat; i++) { int itype = surf->get_type(i); fprintf(f, "Atom %i, k (kappa) = ", i); for (int j = 0; j < 10; j++) { const CrystalSurface::lattice_neighbor_t *neigh = surf->get_neighbors(i); int nneigh = surf->get_number_of_neighbors(i); int n = 0; while (n < nneigh && neigh->neighbor_shell != j) { n++; neigh++; } if (n < nneigh) { int jtype = surf->get_type(neigh->indexj); fprintf(f, "%f (%f) ", second_derivative(itype, jtype, neigh->rnorm), first_derivative(itype, jtype, neigh->rnorm)/ neigh->rnorm); } } fprintf(f, "\n"); } double linf[nat]; linear(surf, linf, error); fprintf(f, "Linear forces on each atom = "); for (int i = 0; i < nat; i++) fprintf(f, "%f ", linf[i]); fprintf(f, "\n"); }
/*! * Linear force contribution for the free surface. */ void FCLJCut::linear(const CrystalSurface *surf, double *linf, Error *error) { mat<double,3> cell(surf->get_cell()); int nat = surf->get_number_of_atoms(); std::fill(linf, linf+nat, 0.0); for (int i = 0; i < nat; i++) { double f = 0.0; int itype = surf->get_type(i); const CrystalSurface::lattice_neighbor_t *neigh = surf->get_neighbors(i); for (int n = 0; n < surf->get_number_of_neighbors(i); n++) { if (neigh->ab <= 0) { int jtype = surf->get_type(neigh->indexj); vec<double,3> e = neigh->r; e /= neigh->rnorm; f += first_derivative(itype, jtype, neigh->rnorm)*e[2]; } neigh++; } linf[i] = -f; } }
void test_functional(int functional) { xc_func_type func; const xc_func_info_type *info; int i, j, k, p_max[6][5]; double max_diff[6][5], avg_diff[6][5], val[5]; #if defined(HAVE_FEENABLEEXCEPT) feenableexcept(FE_INVALID | FE_OVERFLOW); #endif /* initialize functional */ if(xc_func_init(&func, functional, nspin) != 0){ fprintf(stderr, "Functional '%d' not found\n", functional); exit(1); } info = func.info; if(functional == XC_LDA_C_2D_PRM) xc_lda_c_2d_prm_set_params(&func, 10.0); for(k=0; k<6; k++) for(j=0; j<5; j++){ avg_diff[k][j] = 0.0; p_max[k][j] = 0; max_diff[k][j] = -1.0; } for(i=0; xc_trial_points[i][0]!=0.0; i++){ double e, v_fd[5], f_fd[5][5], v_an[5], f_an[5][5]; for(j=0; j<5; j++) v_fd[j] = v_an[j] = 0.0; get_val(xc_trial_points[i], val); /* first, get the analytic gradients */ get_vxc(&func, val, &e, v_an); /* now get the numerical gradients */ first_derivative(&func, val, v_fd, 0); if(info->flags & XC_FLAGS_HAVE_FXC){ int i, j; /* initialize */ for(i=0; i<5; i++) for(j=0; j<5; j++) f_an[i][j] = f_fd[i][j] = 0.0; /* now get the second derivatives */ second_derivatives(&func, val, f_fd); get_fxc(&func, val, f_an); } /* make statistics */ for(j=0; j<5; j++){ double diff = fabs(v_an[j] - v_fd[j]); /* do not test in case of spin unpolarized or if spin down is zero */ if((nspin==1 || val[1]==0.0) && (j!=0 && j!=2)) continue; avg_diff[0][j] += diff; if(diff > max_diff[0][j]){ max_diff[0][j] = diff; p_max[0][j] = i; } if(info->flags & XC_FLAGS_HAVE_FXC){ for(k=0; k<5; k++){ /* do not test in case of spin unpolarized or if spin down is zero */ if((nspin==1 || val[1]==0.0) && (k!=0 && k!=2)) continue; diff = fabs(f_an[k][j] - f_fd[k][j]); avg_diff[k+1][j] += diff; if(diff > max_diff[k+1][j]){ max_diff[k+1][j] = diff; p_max[k+1][j] = i; } } } } } for(k=0; k<6; k++) for(j=0; j<5; j++){ avg_diff[k][j] /= i; } /* print statistics */ { double diff; int i, j; printf("Functional: %s\n", info->name); print_error("Avg.", "vrho", (avg_diff[0][0] + avg_diff[0][1])/2.0, NULL, NULL); j = (max_diff[0][0] > max_diff[0][1]) ? 0 : 1; get_val(xc_trial_points[p_max[0][j]], val); print_error("Max.", "vrho", max_diff[0][j], &func, val); if(info->family > XC_FAMILY_LDA){ print_error("Avg.", "vsig", (avg_diff[0][2] + avg_diff[0][3] + avg_diff[0][4])/3.0, NULL, NULL); j = (max_diff[0][2] > max_diff[0][3]) ? 2 : 3; j = (max_diff[0][j] > max_diff[0][4]) ? j : 4; get_val(xc_trial_points[p_max[0][j]], val); print_error("Max.", "vsig", max_diff[0][j], &func, val); } if(info->flags & XC_FLAGS_HAVE_FXC){ diff = avg_diff[1][0] + avg_diff[1][1] + avg_diff[2][1]; diff = diff/3.0; print_error("Avg.", "v2rho2", diff, NULL, NULL); if(max_diff[1][0] > max_diff[1][1]) {i=1; j=0;} else {i=1; j=1;} if(max_diff[2][1] > max_diff[i][j]) {i=2; j=1;} get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2rho2", max_diff[i][j], &func, val); if(info->family > XC_FAMILY_LDA){ diff = avg_diff[3][0] + avg_diff[4][0] + avg_diff[5][0] + avg_diff[3][1] + avg_diff[4][1] + avg_diff[5][1]; diff = diff/6.0; print_error("Avg.", "v2rhosig", diff, NULL, NULL); if(max_diff[3][0] > max_diff[4][0]) {i=3; j=0;} else {i=4; j=0;} if(max_diff[5][0] > max_diff[i][j]) {i=5; j=0;} if(max_diff[3][1] > max_diff[i][j]) {i=3; j=1;} if(max_diff[4][1] > max_diff[i][j]) {i=4; j=1;} if(max_diff[5][1] > max_diff[i][j]) {i=5; j=1;} get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2rhosig", max_diff[i][j], &func, val); diff = avg_diff[3][2] + avg_diff[4][2] + avg_diff[5][2] + avg_diff[4][3] + avg_diff[5][3] + avg_diff[5][4]; diff = diff/6.0; print_error("Avg.", "v2sig2", diff, NULL, NULL); if(max_diff[3][2] > max_diff[4][2]) {i=3; j=2;} else {i=4; j=2;} if(max_diff[5][2] > max_diff[i][j]) {i=5; j=2;} if(max_diff[4][3] > max_diff[i][j]) {i=4; j=3;} if(max_diff[5][3] > max_diff[i][j]) {i=5; j=3;} if(max_diff[5][4] > max_diff[i][j]) {i=5; j=4;} get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2sig2", max_diff[i][j], &func, val); } } } xc_func_end(&func); }
void print_error(char *type, char *what, double diff, xc_func_type *func, double *p) { static char *red="\033[31;1m", *norm="\033[0m"; char *color; color = (diff > 5e-4) ? red : norm; printf("%s error %s: %s%g%s\n", type, what, color, diff, norm); if(func == NULL) return; printf(" point (% 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e)\n", p[0], p[1], p[2], p[3], p[4]); if(strcmp(what, "vrho")==0 || strcmp(what, "vsig")==0){ double e, v_an[5], v_fd[5]; int j; for(j=0; j<5; j++) v_fd[j] = v_an[j] = 0.0; get_vxc(func, p, &e, v_an); first_derivative(func, p, v_fd, 0); if(strcmp(what, "vrho") == 0){ printf(" analyt (% 8.2e, % 8.2e)\n", v_an[0], v_an[1]); printf(" fd (% 8.2e, % 8.2e)\n", v_fd[0], v_fd[1]); } if(strcmp(what, "vsig") == 0){ printf(" analyt (% 8.2e, % 8.2e, % 8.2e)\n", v_an[2], v_an[3], v_an[4]); printf(" fd (% 8.2e, % 8.2e, % 8.2e)\n", v_fd[2], v_fd[3], v_fd[4]); } } if(strcmp(what, "v2rho2")==0 || strcmp(what, "v2rhosig")==0 || strcmp(what, "v2sig2")==0){ double f_an[5][5], f_fd[5][5]; int i, j; get_fxc(func, p, f_an); second_derivatives(func, p, f_fd); if(strcmp(what, "v2rho2") == 0){ printf(" analyt (% 8.2e, % 8.2e, % 8.2e)\n", f_an[0][0], f_an[0][1], f_an[1][1]); printf(" fd (% 8.2e, % 8.2e, % 8.2e)\n", f_fd[0][0], f_fd[0][1], f_fd[1][1]); } if(strcmp(what, "v2rhosig") == 0){ printf(" analyt (% 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e)\n", f_an[2][0], f_an[3][0], f_an[4][0], f_an[2][1], f_an[3][1], f_an[4][1]); printf(" fd (% 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e)\n", f_fd[2][0], f_fd[3][0], f_fd[4][0], f_fd[2][1], f_fd[3][1], f_fd[4][1]); } if(strcmp(what, "v2sig2") == 0){ printf(" analyt (% 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e)\n", f_an[2][2], f_an[3][2], f_an[4][2], f_an[3][3], f_an[4][3], f_an[4][4]); printf(" fd (% 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e, % 8.2e)\n", f_fd[2][2], f_fd[3][2], f_fd[4][2], f_fd[3][3], f_fd[4][3], f_fd[4][4]); } } }
void test_functional(int functional) { functionals_type func; const xc_func_info_type *info; int i, j, k, p_max[6][5]; double max_diff[6][5], avg_diff[6][5], val[5]; /* initialize functional */ func.family = xc_family_from_id(functional); switch(func.family) { case XC_FAMILY_LDA: if(functional == XC_LDA_X) xc_lda_x_init(&(func.lda_func), nspin, 3, 0); else xc_lda_init(&(func.lda_func), functional, nspin); info = func.lda_func.info; break; case XC_FAMILY_GGA: xc_gga_init(&(func.gga_func), functional, nspin); info = func.gga_func.info; break; case XC_FAMILY_HYB_GGA: xc_hyb_gga_init(&(func.hyb_gga_func), functional, nspin); info = func.hyb_gga_func.info; break; default: fprintf(stderr, "Functional '%d' not found\n", functional); exit(1); } for(k=0; k<6; k++) for(j=0; j<5; j++) { avg_diff[k][j] = 0.0; p_max[k][j] = 0; max_diff[k][j] = -1.0; } for(i=0; xc_trial_points[i][0]!=0.0; i++) { double e, v_fd[5], f_fd[5][5], v_an[5], f_an[5][5]; for(j=0; j<5; j++) v_fd[j] = v_an[j] = 0.0; get_val(xc_trial_points[i], val); /* first, get the analitic gradients */ get_vxc(&func, val, &e, v_an); /* now get the numerical gradients */ first_derivative(&func, val, v_fd, 0); if(info->provides & XC_PROVIDES_FXC) { int i, j; /* initialize */ for(i=0; i<5; i++) for(j=0; j<5; j++) f_an[i][j] = f_fd[i][j] = 0.0; /* now get the second derivatives */ second_derivatives(&func, val, f_fd); get_fxc(&func, val, f_an); } /* make statistics */ for(j=0; j<5; j++) { double diff = fabs(v_an[j] - v_fd[j]); /* do not test in case of spin unpolarized or if spin down is zero */ if((nspin==1 || val[1]==0.0) && (j!=0 && j!=2)) continue; avg_diff[0][j] += diff; if(diff > max_diff[0][j]) { max_diff[0][j] = diff; p_max[0][j] = i; } if(info->provides & XC_PROVIDES_FXC) { for(k=0; k<5; k++) { /* do not test in case of spin unpolarized or if spin down is zero */ if((nspin==1 || val[1]==0.0) && (k!=0 && k!=2)) continue; diff = fabs(f_an[k][j] - f_fd[k][j]); avg_diff[k+1][j] += diff; if(diff > max_diff[k+1][j]) { max_diff[k+1][j] = diff; p_max[k+1][j] = i; } } } } } for(k=0; k<6; k++) for(j=0; j<5; j++) { avg_diff[k][j] /= i; } /* print statistics */ { double diff; int i, j; printf("Functional: %s\n", info->name); print_error("Avg.", "vrho", (avg_diff[0][0] + avg_diff[0][1])/2.0, NULL, NULL); j = (max_diff[0][0] > max_diff[0][1]) ? 0 : 1; get_val(xc_trial_points[p_max[0][j]], val); print_error("Max.", "vrho", max_diff[0][j], &func, val); if(func.family > XC_FAMILY_LDA) { print_error("Avg.", "vsig", (avg_diff[0][2] + avg_diff[0][3] + avg_diff[0][4])/3.0, NULL, NULL); j = (max_diff[0][2] > max_diff[0][3]) ? 2 : 3; j = (max_diff[0][j] > max_diff[0][4]) ? j : 4; get_val(xc_trial_points[p_max[0][j]], val); print_error("Max.", "vsig", max_diff[0][j], &func, val); } if(info->provides & XC_PROVIDES_FXC) { diff = avg_diff[1][0] + avg_diff[1][1] + avg_diff[2][1]; diff = diff/3.0; print_error("Avg.", "v2rho2", diff, NULL, NULL); if(max_diff[1][0] > max_diff[1][1]) { i=1; j=0; } else { i=1; j=1; } if(max_diff[2][1] > max_diff[i][j]) { i=2; j=1; } get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2rho2", max_diff[i][j], &func, val); if(func.family > XC_FAMILY_LDA) { diff = avg_diff[3][0] + avg_diff[4][0] + avg_diff[5][0] + avg_diff[3][1] + avg_diff[4][1] + avg_diff[5][1]; diff = diff/6.0; print_error("Avg.", "v2rhosig", diff, NULL, NULL); if(max_diff[3][0] > max_diff[4][0]) { i=3; j=0; } else { i=4; j=0; } if(max_diff[5][0] > max_diff[i][j]) { i=5; j=0; } if(max_diff[3][1] > max_diff[i][j]) { i=3; j=1; } if(max_diff[4][1] > max_diff[i][j]) { i=4; j=1; } if(max_diff[5][1] > max_diff[i][j]) { i=5; j=1; } get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2rhosig", max_diff[i][j], &func, val); diff = avg_diff[3][2] + avg_diff[4][2] + avg_diff[5][2] + avg_diff[4][3] + avg_diff[5][3] + avg_diff[5][4]; diff = diff/6.0; print_error("Avg.", "v2sig2", diff, NULL, NULL); if(max_diff[3][2] > max_diff[4][2]) { i=3; j=2; } else { i=4; j=2; } if(max_diff[5][2] > max_diff[i][j]) { i=5; j=2; } if(max_diff[4][3] > max_diff[i][j]) { i=4; j=3; } if(max_diff[5][3] > max_diff[i][j]) { i=5; j=3; } if(max_diff[5][4] > max_diff[i][j]) { i=5; j=4; } get_val(xc_trial_points[p_max[i][j]], val); print_error("Max.", "v2sig2", max_diff[i][j], &func, val); } } } }
void first_derivative_spinpolarized(functionals_type *func, double point[7], double der[5], int which) { first_derivative(func, point, der, which, XC_POLARIZED); }