/*******************************/ /* Lattice Dynamics of Argon */ /* */ /* Ver 1.1 June.13, 1998 */ /* Developed by Ju Li (MIT) */ /*******************************/ /* Version Notes: 1. TTY interface. 2. Woon's pair potential. 3. Upon request, save the real space dynamical matrices of atom(s) on a .dm file so if it is a perfect crystal, it can be used by dm.m to plot out the phonon dispersion curves. 4. Calculate and diagonalize the dynamical matrix for arbitrary configuration and save the eigenmodes on a .eig file, which can be handled by collect.m. 5. User-defined supercell k sampling or random sampling. 6. Upon request, evaluate DOS and LDOS(s). */ #include #include #include #include "diag.h" int main() { int i,j,k,l,m,ip; double cc, dd, ee; char *p; /* Read instructions from input, such as "don" file */ printf ("Reading in instructions...\n"); fscanf (stdin, "Name of configuration (->*, default=fcc_unit_cell):\n%s\n\n", config_name); if (!strcasecmp(config_name,"default")) sprintf(config_name, "fcc_unit_cell"); fscanf (stdin, "Load configuration from file (default=*):\n%s\n\n", fn_config_read); if (!strcasecmp(fn_config_read,"default")) sprintf(fn_config_read, "%s", config_name); fscanf (stdin, "Apply affine transformation (11,22,33,21=12,31=13,32=23):\n"); fscanf (stdin, "%lf %lf %lf %lf %lf %lf\n\n", &M[0][0], &M[1][1], &M[2][2], &M[0][1], &M[0][2], &M[1][2]); /* symmetrize */ M[1][0] = M[0][1]; M[2][0] = M[0][2]; M[2][1] = M[1][2]; fscanf (stdin, "Save real-space dynamical matrices on file\n"); fscanf (stdin, "(NULL=don't, default=*.dm):\n%s\n\n", fn_dm); if (save_dm=strcasecmp(fn_dm, "NULL")) if (!strcasecmp(fn_dm, "default")) sprintf(fn_dm, "%s.dm", config_name); fscanf (stdin, "Supercell k-point sampling file (if numeric then\n"); fscanf (stdin, "apply random sampling in BZ, default=Kpts/fcckpt.10):\n%s\n\n", fn_kpt); if (random_k_sampling=((*fn_kpt>='0')&&(*fn_kpt<='9'))) { /* user inputs a integer, do random k sampling */ for (p=fn_kpt;(*p>='0')&&(*p<='9');p++); *p = 0; sscanf(fn_kpt, "%d", &num_kpts); } else if (!strcasecmp(fn_kpt, "default")) sprintf(fn_kpt, "Kpts/fcckpt.10"); fscanf (stdin, "Save normal modes on file (NULL=don't, default=*.eig):\n%s\n\n", fn_eig); if (save_eig=strcasecmp(fn_eig, "NULL")) if (!strcasecmp(fn_eig, "default")) sprintf(fn_eig, "%s.eig", config_name); fscanf (stdin, "List atoms (NULL=don't, default=all atoms):\n%s\n\n", ldos_atom_list); fscanf (stdin, "Save DOS on file (NULL=don't, default=*.out):\n%s\n\n", fn_dos); if (save_dos=strcasecmp(fn_dos, "NULL")) if (!strcasecmp(fn_dos, "default")) sprintf(fn_dos, "%s.out", config_name); fscanf (stdin, "Save LDOS on file (NULL=don't, default=*_ldos.out):\n%s\n\n", fn_ldos); if (save_ldos=strcasecmp(fn_ldos, "NULL")) if (!strcasecmp(fn_ldos, "default")) sprintf(fn_ldos, "%s_ldos.out", config_name); fscanf (stdin, "Minimum frequency (in THz):\n%lf\n\n", &minfreq); fscanf (stdin, "Maximum frequency (in THz):\n%lf\n\n", &maxfreq); fscanf (stdin, "How many bins to represent DOS and LDOS:\n%d\n\n", &num_bins); delfreq = (maxfreq-minfreq)/num_bins; fscanf (stdin, "Random number generator seed (long integer):\n%ld\n\n", &iseed); srandom (iseed); fscanf (stdin, "Pair potential to be used (LJ6_12 or WOON):\n%s\n\n", potential_function); LJ6_12 = !strcmp(potential_function,"LJ6_12"); WOON = !strcmp(potential_function,"WOON"); if ((!LJ6_12) && (!WOON)) { fprintf (stdout, "\n **Error: Choose between LJ6_12 or WOON pair potential\n"); exit(1); } printf("Instructions read complete.\n\n"); /* Instructions read complete */ printf ("Vibrational eigenmodes will be calculated for \"%s\"\n", config_name); printf ("using %s potential with Rcut = %f = %f Angstrom.\n\n", potential_function, CUTOFF, CUTOFF*ULENGTH_IN_ANGSTROM); printf ("The configuration is being loaded from \"%s\".\n", fn_config_read); if ((filehandle=fopen(fn_config_read, "r"))==NULL) { fprintf(stdout, "\n **Error: cannot locate file \"%s\"\n.", fn_config_read); exit(1); } fscanf (filehandle, "Number of particles = %d\n\n", &np); printf ("Allocate simple arrays for %d particles.\n\n",np); s = (double *) malloc(3*np*sizeof(double)); mass = (double *) malloc(np*sizeof(double)); if (save_dos) { dos = (double *) malloc (num_bins*sizeof(double)); for (i=0; i 0.85*MAXDENSITY) { printf("Current density %f is above 85%% of MAXDENSITY %f in \"diag.h\".\n", np/volume, MAXDENSITY); printf ("Overflow feared. Please increase MAXDENSITY in \"diag.h\".\n"); exit(1); } /* read in reduced coordinates from configuration file */ fscanf(filehandle, "Mass(amu) sx sy sz sx1(1/ps) sy1(1/ps) sz1(1/ps)\n"); for (i=0;i<3*np;i+=3) { fscanf (filehandle, "%lf %lf %lf %lf %lf %lf %lf\n", &mass[i/3], &s[i], &s[i+1], &s[i+2], &cc, &cc, &cc); /* convert from AMU to reduced mass unit */ mass[i/3] = mass[i/3]/AVO*1E-3/UMASS_IN_KG; } fclose (filehandle); printf ("Configuration \"%s\" generated successfully on the computer.\n\n", config_name); /* count the total number of interactions */ printf ("Counting all possible (image) interactions within Rcut = %fA.\n", CUTOFF*ULENGTH_IN_ANGSTROM); for (num_dm=0,k=0,i=0; iMAX_LDOS_ATOM_BRACKETS) { printf ("number of brackets more than MAX_LDOS_ATOM_BRACKETS.\n"); exit(1); } } /* find out how many atoms we need to keep track of */ printf ("Number of brackets recognized = %d. They are\n", num_ldos_atom_brackets); for (num_ldos_atoms=0,i=0; i\n"); } if (k%(int)ceil(10000./np/np/np)==0) printf ("Doing k-point %d.\n", k); /* assemble the k-space dynamical matrix */ for (i=0; i<3*np*(3*np+1); i++) ap[i]=0.; for (ip=0; ip=0.)?sqrt(w[l]):-sqrt(-w[l]); if (save_eig) fprintf (filehandle, "%f ", w[l]); /* frequency bin index */ ip = floor((w[l]-minfreq)/delfreq); if (save_dos) dos[ip] += kpts[4*k+3]; for (m=0,i=0; iMAX_STRING_LENGTH)) break; if ((*p>='0')&&(*p<='9')) { /* read in a pair */ strcpy(buffer, p); for (q=buffer;(*q>='0')&&(*q<='9');q++);*q=0; /* read in head */ sscanf(buffer, "%d", head+number_of_brackets); for (q++;(!((*q>='0')&&(*q<='9')))&&(*q!=0);q++); /* if there is no tail */ if (*q==0) { tail[number_of_brackets]=head[number_of_brackets]; return (number_of_brackets+1); } else { /* read in tail */ for (r=q;(*q>='0')&&(*q<='9');q++);*q=0; sscanf(r,"%d",tail+number_of_brackets); number_of_brackets++; p+=q-buffer; } } p++; } return number_of_brackets; } /* end parse_number_string() */ double matinv(double A[3][3], double B[3][3]) { double D11,D22,D33,D12,D21,D13,D31,D32,D23,volume; D11=A[1][1]*A[2][2]-A[1][2]*A[2][1]; D22=A[2][2]*A[0][0]-A[2][0]*A[0][2]; D33=A[0][0]*A[1][1]-A[0][1]*A[1][0]; D12=A[1][2]*A[2][0]-A[1][0]*A[2][2]; D23=A[2][0]*A[0][1]-A[2][1]*A[0][0]; D31=A[0][1]*A[1][2]-A[0][2]*A[1][1]; D13=A[1][0]*A[2][1]-A[2][0]*A[1][1]; D21=A[2][1]*A[0][2]-A[0][1]*A[2][2]; D32=A[0][2]*A[1][0]-A[1][2]*A[0][0]; volume=A[0][0]*D11+A[0][1]*D12+A[0][2]*D13; B[0][0]=D11/volume; B[1][1]=D22/volume; B[2][2]=D33/volume; B[0][1]=D21/volume; B[1][2]=D32/volume; B[2][0]=D13/volume; B[1][0]=D12/volume; B[2][1]=D23/volume; B[0][2]=D31/volume; return (volume); } /* end matinv() */ /* returns pseudo-random number on (0,1) */ double frandom() { return ((random()+0.5)/pow((double)2, (double)31)); } /* end frandom() */