double df1dim(double x) { int j; double df1=0.0; matrix xt=NULL,df=NULL; alloc_mtx(&xt,dncom,1); alloc_mtx(&df,dncom,1); for (j=1;j<=dncom;j++) xt[j][1]=dpcom[j][1]+x*dxicom[j][1]; (*nrdfun)(xt,df); for (j=1;j<=dncom;j++) df1 += df[j][1]*dxicom[j][1]; free_mtx(&df); free_mtx(&xt); return (df1); }
//calculate energies for isolated molecules //if we don't know it, calculate it and save the value double calc_e_iso ( system_t * system, double * sqrtKinv, molecule_t * mptr ) { int nstart, nsize; // , curr_dimM; (unused variable) double e_iso; //total vdw energy of isolated molecules struct mtx * Cm_iso; //matrix Cm_isolated double * eigvals; //eigenvalues of Cm_cm molecule_t * molecule_ptr; atom_t * atom_ptr; nstart=nsize=0; //loop through each individual molecule for ( molecule_ptr = system->molecules; molecule_ptr; molecule_ptr=molecule_ptr->next ) { if ( molecule_ptr != mptr ) { //count atoms then skip to next molecule for ( atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next ) nstart++; continue; } //now that we've found the molecule of interest, count natoms, and calc energy for ( atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next ) nsize++; //build matrix for calculation of vdw energy of isolated molecule Cm_iso = build_M(3*(nsize), 3*nstart, system->A_matrix, sqrtKinv); //diagonalize M and extract eigenvales -> calculate energy eigvals=lapack_diag(Cm_iso,1); //no eigenvectors e_iso=eigen2energy(eigvals,Cm_iso->dim,system->temperature); //free memory free(eigvals); free_mtx(Cm_iso); //convert a.u. -> s^-1 -> K return e_iso * au2invsec * halfHBAR ; } //unmatched molecule return NAN; //we should never get here }
//returns interaction VDW energy double vdw(system_t *system) { int N; // dimC; (unused variable) //number of atoms, number of non-zero rows in C-Matrix double e_total, e_iso; //total energy, isolation energy (atoms @ infinity) double * sqrtKinv; //matrix K^(-1/2); cholesky decomposition of K double ** Am = system->A_matrix; //A_matrix struct mtx * Cm; //C_matrix (we use single pointer due to LAPACK requirements) double * eigvals; //eigenvales double fh_corr, lr_corr; N=system->natoms; //allocate arrays. sqrtKinv is a diagonal matrix. d,e are used for matrix diag. sqrtKinv = getsqrtKinv(system,N); //calculate energy vdw of isolated molecules e_iso = sum_eiso_vdw ( system, sqrtKinv ); //Build the C_Matrix Cm = build_M (3*N, 0, Am, sqrtKinv); //setup and use lapack diagonalization routine dsyev_() eigvals = lapack_diag (Cm, system->polarvdw); //eigenvectors if system->polarvdw == 2 if ( system->polarvdw == 2 ) printevects(Cm); //return energy in inverse time (a.u.) units e_total = eigen2energy(eigvals, Cm->dim, system->temperature); e_total *= au2invsec * halfHBAR; //convert a.u. -> s^-1 -> K //vdw energy comparison if ( system->polarvdw == 3 ) printf("VDW Two-Body | Many Body = %lf | %lf\n", twobody(system),e_total-e_iso); if ( system->feynman_hibbs ) { if ( system->vdw_fh_2be ) fh_corr = fh_vdw_corr_2be(system); //2be method else fh_corr = fh_vdw_corr(system); //mpfd } else fh_corr=0; if ( system->rd_lrc ) lr_corr = lr_vdw_corr(system); else lr_corr=0; //cleanup and return free(sqrtKinv); free(eigvals); free_mtx(Cm); return e_total - e_iso + fh_corr + lr_corr; }
//calculate T matrix element for a particular separation double e2body(system_t * system, atom_t * atom, pair_t * pair, double r) { double energy; double lr = system->polar_damp * r; double lr2 = lr*lr; double lr3 = lr*lr2; double Txx = pow(r,-3)*(-2.0+(0.5*lr3+lr2+2*lr+2)*exp(-lr)); double Tyy = pow(r,-3)*(1-(0.5*lr2+lr+1)*exp(-lr)); double * eigvals; struct mtx * M = alloc_mtx(6); //only the sub-diagonals are non-zero M->val[1]=M->val[2]=M->val[4]=M->val[5]=M->val[6]=M->val[8]=M->val[9]=M->val[11]=0; M->val[12]=M->val[13]=M->val[15]=M->val[16]=M->val[19]=M->val[20]=M->val[22]=M->val[23]=0; M->val[24]=M->val[26]=M->val[27]=M->val[29]=M->val[30]=M->val[31]=M->val[33]=M->val[34]=0; //true diagonals M->val[0]=M->val[7]=M->val[14]=(atom->omega)*(atom->omega); M->val[21]=M->val[28]=M->val[35]=(pair->atom->omega)*(pair->atom->omega); //sub-diagonals M->val[3]=M->val[18]= (atom->omega)*(pair->atom->omega)*sqrt(atom->polarizability*pair->atom->polarizability)*Txx; M->val[10]=M->val[17]=M->val[25]=M->val[32]= (atom->omega)*(pair->atom->omega)*sqrt(atom->polarizability*pair->atom->polarizability)*Tyy; eigvals=lapack_diag(M,1); energy = eigen2energy(eigvals, 6, system->temperature); //subtract energy of atoms at infinity // energy -= 3*wtanh(atom->omega, system->temperature); energy -= 3*atom->omega; // energy -= 3*wtanh(pair->atom->omega, system->temperature); energy -= 3*pair->atom->omega; free(eigvals); free_mtx(M); return energy * au2invsec * halfHBAR; }