/* * Use DIIS to help SCF */ void calculateSCFDIIS(molecule_t *molecule) { #define EPS 0.0000000000001 #define DEL 0.0000000000001 double **fs[6], **es[6], **b, *c; int **piv; hamiltonian(molecule); sqrtMolecule(molecule); int n = molecule->orbitals; //So that the same thing does not need to be typed repeatedly. int count = 0; double elec, energy = 0, elast, rms; double **f0, **f1, **f2, **c0, **c1, **d0, **d1, **work1, **work2, **work3, **ham, **shalf, **s; double **sort; f0 = calloc_contiguous(2, sizeof(double), n, n); f1 = calloc_contiguous(2, sizeof(double), n, n); f2 = calloc_contiguous(2, sizeof(double), n, n); c0 = calloc_contiguous(2, sizeof(double), n, n); c1 = calloc_contiguous(2, sizeof(double), n, n); d0 = calloc_contiguous(2, sizeof(double), n, n); d1 = calloc_contiguous(2, sizeof(double), n, n); work1 = calloc_contiguous(2, sizeof(double), n, n); work2 = calloc_contiguous(2, sizeof(double), n, n); work3 = calloc_contiguous(2, sizeof(double), n, n); ham = calloc_contiguous(2, sizeof(double), n, n); shalf = calloc_contiguous(2, sizeof(double), n, n); sort = calloc_contiguous(2, sizeof(double), n, n); b = calloc_contiguous(2, sizeof(double), 7, 7); c = calloc(7, sizeof(double)); s = calloc_contiguous(2, sizeof(double), n, n); piv = calloc_contiguous(2, sizeof(double), 7, 7); for(int i = 0; i < 6; i++) { fs[i] = calloc_contiguous(2, sizeof(double), n, n); es[i] = calloc_contiguous(2, sizeof(double), n, n); } for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { s[i][j] = molecule->overlap[i][j]; shalf[i][j] = molecule->symmetric[i][j]; } } printf("\nElec\t\tEnergy\t\tDiff\t\tRMS\n"); do { elast = energy; if(count == 0) { for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { //Find the initial Fock guess. f0[i][j] = ham[i][j] = molecule->hamiltonian[i][j]; } } } else { memcpy(*d1, *d0, n * n * sizeof(double)); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { f0[i][j] = ham[i][j]; for(int k = 0; k < n; k++) { for(int l = 0; l < n; l++) { f0[i][j] += d0[k][l] * (2 * molecule->two_electron[TEI(i, j, k, l)] - molecule->two_electron[TEI(i, k, j, l)]); } } } } } //DIIS extrapolation. memcpy(*(fs[count % 6]), *f0, n * n * sizeof(double)); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *s, n, *d0, n, 0, *work1, n); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *work1, n, *f0, n, 0, *work2, n); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *f0, n, *d0, n, 0, *work1, n); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *work1, n, *s, n, 0, *work3, n); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { es[count % 6][i][j] = work3[i][j] - work2[i][j]; } } if(count >= 6) { for(int i = 0; i < ((count > 6)? 6: count); i++) { for(int j = 0; j < ((count > 6)? 6: count); j++) { b[i][j] = 0; for(int k = 0; k < n; k++) { for(int l = 0; l < n; l++) { b[i][j] += es[i][k][l] * es[j][k][l]; } } } } if(count < 6) { for(int i = 0; i < 6; i++) { for(int j = 0; j < 6; j++) { if(i < count && j < count) { continue; } if(i == j) { b[i][j] = 1; } else { b[i][j] = 0; } } } } for(int i = 0; i < 6; i++) { b[6][i] = -1; b[i][6] = -1; c[i] = 0; } b[6][6] = 0; c[6] = -1; LAPACKE_dgesv(LAPACK_ROW_MAJOR, 7, 1, *b, 7, *piv, c, 1); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { f2[i][j] = 0; for(int m = 0; m < 6; m++) { f2[i][j] += c[m] * fs[m][i][j]; } } } cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, n, n, n, 1.0, *shalf, n, *f2, n, 0, *work1, n); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *work1, n, *shalf, n, 0, *f1, n); } else { cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, n, n, n, 1.0, *shalf, n, *f0, n, 0, *work1, n); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *work1, n, *shalf, n, 0, *f1, n); } memset(work1[0], 0, n * n * sizeof(double)); memset(work2[0], 0, n * n * sizeof(double)); memset(work3[0], 0, n * n * sizeof(double)); LAPACKE_dgeev(LAPACK_ROW_MAJOR, 'N', 'V', n, *f1, n, *work1, *work2, *work3, n, *c1, n); //Prepare for sorting. for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { work2[i][j] = c1[i][j]; } } //Sort for(int i = 0; i < n; i++) { sort[i] = work1[0] + i; } qsort(sort, n, sizeof(double *), comparedd); //Sift through data. for(int i = 0; i < n; i++) { unsigned long off = ((unsigned long) sort[i] - (unsigned long) work1[0]); off /= sizeof(double); for(int j = 0; j < n; j++) { c1[j][i] = work2[j][off]; } } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, *shalf, n, *c1, n, 0, *c0, n); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { d0[i][j] = 0; for(int k = 0; k < molecule->electrons / 2; k++) { d0[i][j] += c0[i][k] * c0[j][k]; } } } elec = 0; for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { elec += d0[i][j] * (ham[i][j] + f0[i][j]); } } energy = elec + molecule->enuc; rms = 0; for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { rms += (d0[i][j] - d1[i][j]) * (d0[i][j] - d1[i][j]); } } rms = sqrt(rms); count++; printf("%d\t%.15f\t%.15f\t%.15f\t%.15f\n", count, elec, energy, fabs(elast - energy), rms); } while(count < 100 && (fabs(elast - energy) > EPS && rms > DEL)); molecule->scf_energy = energy; for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { molecule->density[i][j] = d0[i][j]; molecule->fock[i][j] = f0[i][j]; molecule->molecular_orbitals[i][j] = c0[i][j]; molecule->molecular_eigs[i][j] = ((i == j)? sort[i][0]: 0); } } free_mult_contig(16, c0, c1, d0, d1, f0, f1, f2, ham, shalf, work1, work2, work3, sort, b, c, s); for(int i = 0; i < 6; i++) { free(fs[i]); free(es[i]); } }
template <> inline int geev(const char order, const char jobVL, const char jobVR, const int N, double *A, const int LDA, double *WR, double *WI, double *VL, const int LDVL, double *VR, const int LDVR) { return LAPACKE_dgeev(order, jobVL, jobVR, N, A, LDA, WR, WI, VL, LDVL, VR, LDVR); }