//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2010 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // dynmat.C: compute and diagonalize a dynamical matrix // //////////////////////////////////////////////////////////////////////////////// // Forces are read from Qbox output // The Qbox output should correspond to a sequence of calculations // using symmetric finite displacements for all atoms in the x,y,z directions // Displacements have an amplitude of +/- h // // use: dynmat force.dat h Nat1 mass1 [Nat2 mass2] ... // input_file: force.dat: forces from Qbox XML output file (collected with grep) // h: displacement used in the force calculations (a.u.) // Nat1: number of atoms of mass mass1 // Nat2: (optional) number of atoms of mass mass2 // (repeat the above for all atomic species) // Species masses must be given in the order in which they appear in the // element in Qbox output #include #include #include #include #include #include #include #include #include using namespace std; extern "C" void dsyev_(const char *jobz, const char *uplo, const int *n, double *a, const int *lda, double *w, double *wrk, int *lwrk, int *info); int main(int argc, char **argv) { if ( argc < 5 ) { cout << "use: dynmat force.dat h nat1 mass1 [nat2 mass2] ..." << endl; return 1; } char* infilename = argv[1]; ifstream infile(infilename); const double h = atof(argv[2]); // cout << "h=" << h << endl; const double Ha2cm1 = 219474.65; vector mass; for ( int iarg = 3; iarg < argc; iarg++, iarg++ ) { // read number of atoms and mass for each species const int n = atoi(argv[iarg]); const double m = atof(argv[iarg+1]); // cout << n << " atoms of mass " << m << endl; for ( int i = 0; i < n; i++ ) mass.push_back(1822.89*m); } const int nat = mass.size(); // read forces double f[2][nat][3][nat][3]; double fx,fy,fz; string dum; for ( int ia1 = 0; ia1 < nat; ia1++ ) { for ( int idir1 = 0; idir1 < 3; idir1++ ) { for ( int ishift = 0; ishift < 2; ishift++ ) { for ( int ia2 = 0; ia2 < nat; ia2++ ) { infile >> dum >> fx >> fy >> fz; while (infile.get() != '\n'); f[ishift][ia1][idir1][ia2][0] = fx; f[ishift][ia1][idir1][ia2][1] = fy; f[ishift][ia1][idir1][ia2][2] = fz; } } } } // compute matrix elements: centered finite difference // a[3*ia1+idir1][3*ia2+idir2] = // ( f[1][ia1][idir1][ia2][idir2] - f[0][ia1][idir1][ia2][idir2] ) / ( 2 h ) const int n = 3*nat; valarray a(n*n); for ( int ia1 = 0; ia1 < nat; ia1++ ) { for ( int idir1 = 0; idir1 < 3; idir1++ ) { for ( int ia2 = 0; ia2 < nat; ia2++ ) { for ( int idir2 = 0; idir2 < 3; idir2++ ) { int i = 3*ia1+idir1; int j = 3*ia2+idir2; double aij = ( f[1][ia1][idir1][ia2][idir2] - f[0][ia1][idir1][ia2][idir2] ) / ( 2.0 * h ); aij = aij / sqrt(mass[ia1]*mass[ia2]); a[j*n+i] = aij; } } } } // cout << a; valarray w_upper(n),w_lower(n),w_sym(n); valarray asave(a); char jobz = 'n'; char uplo = 'u'; int lwrk = 3*n; valarray wrk(lwrk); // use the upper part of the dynamical matrix int info; dsyev_(&jobz,&uplo,&n,&a[0],&n,&w_upper[0],&wrk[0],&lwrk,&info); assert(info==0); a = asave; // use the lower part of the dynamical matrix uplo = 'l'; dsyev_(&jobz,&uplo,&n,&a[0],&n,&w_lower[0],&wrk[0],&lwrk,&info); assert(info==0); a = asave; // symmetrize the matrix a for ( int i = 0; i < n; i++ ) { for ( int j = i+1; j < n; j++ ) { double aij = 0.5 * ( a[j*n+i] + a[i*n+j] ); a[j*n+i] = aij; a[i*n+j] = aij; } } // compute eigenvectors jobz = 'v'; dsyev_(&jobz,&uplo,&n,&a[0],&n,&w_sym[0],&wrk[0],&lwrk,&info); assert(info==0); cout << " frequencies (upper/lower/sym):" << endl; for ( int i = 0; i < n; i++ ) { if ( w_upper[i] < 0.0 ) cout << setw(8) << (int) (Ha2cm1 * sqrt(-w_upper[i])) << " I"; else cout << setw(8) << (int) (Ha2cm1 * sqrt(w_upper[i])); if ( w_lower[i] < 0.0 ) cout << setw(8) << (int) (Ha2cm1 * sqrt(-w_lower[i])) << " I"; else cout << setw(8) << (int) (Ha2cm1 * sqrt(w_lower[i])); if ( w_sym[i] < 0.0 ) cout << setw(8) << (int) (Ha2cm1 * sqrt(-w_sym[i])) << " I"; else cout << setw(8) << (int) (Ha2cm1 * sqrt(w_sym[i])); cout << endl; } ofstream vecfile("dynmat_eigvec.dat"); for ( int j = 0; j < n; j++ ) { vecfile << "# mode " << j+1 << " frequency = "; if ( w_sym[j] < 0.0 ) vecfile << setw(8) << (int) (Ha2cm1 * sqrt(-w_sym[j])) << " I"; else vecfile << setw(8) << (int) (Ha2cm1 * sqrt(w_sym[j])); vecfile << " cm-1" << endl; vecfile << setprecision(8); vecfile.setf(ios::fixed, ios::floatfield); vecfile.setf(ios::right, ios::adjustfield); for ( int i = 0; i < n; i+=3 ) vecfile << i/3+1 << " " << setw(12) << a[j*n+i] << " " << setw(12) << a[j*n+i+1] << " " << setw(12) << a[j*n+i+2] << endl; } }