/********************************************************** xvibs version 4.0.1 (August 1997) This program produces XYZ animation files for molecular vibrations represented by normal modes taken from output files from Aces2, Gamess, and Gaussian. The program autosenses what output file is given. It writes separate files, one simple cosine trajectory for particular normal mode. Vectors representing the normal coordinate are attached to the atoms, which is useful for a static picture. This program is not copyrighted. You are welcome to extend it, or send your files to basmith@pollux.chem.umn.edu and I will gladly extend it for you. Send bug reports to: basmith@pollux.chem.umn.edu Compiling: cc -o xvibs xvibs.c -lm Running: xvibs file {all | 1..(3*N-6)} [palindrome] Example: xvibs ch3oh_gam.out all Output files are named ch3oh_gam.{001-018}.xyz or xvibs ch3oh_gam.out 15 for mode 15 only. Output will be ch3oh_gam.015.xyz By default, XYZ files created are for loop animation (like in XMol). The optional 3rd argument "palindrome" will create XYZ files for palindrome animation (like in Chime). Examples are provided for ACES2, GAMESS, and GAUSSIAN files. **********************************************************/ /********************************************************** Written in 1990 by Milan Hodoscek Institute of Chemistry, Ljubljana, Slovenia Modified for XMOL 1992 @NIH, Bethesda, MD Modified again Fred Brouwer Univ. of Amsterdam 1994 to include vectors (fred@org.chem.uva.nl (Fred Brouwer)) Modified to accept G94, Yos Ginting (Yos.Ginting@chem.utas.edu.au) Modified by Jan Labanowski, jkl@ccl.net to accept input from GAMESS and ACESS Rewritten by Bradley A. Smith, (http://pollux.chem.umn.edu/~basmith/, basmith@pollux.chem.umn.edu) Send bug reports to: basmith@pollux.chem.umn.edu ------------------------------------------- History: Version 2 (June 1994) -- Fixed bug to accept file names without point -- Maximum number of atoms is now define with MAXAT -- Added data for drawing vectors representing normal modes -- Prints energy for G90 and G92 output Version 3 (July 1996) Yos Ginting -- Add capability to parse G94 output. The folowing two function were added: is_g94 , return 1 if input is in G94 format return 0 if it is in G92 format otherwise, display error messages vib_g94 is a modification of vib_g88. It now properly parses g94 output Version 3.1 (July 1997) Jan K. Labanowski -- replaced is_94 with which_program, and g94 with file_type The which_program returns the code (look up the #define statements) which represents the type of format of OUTPUT file. Added global variables: vibtotal -- provides info on how many vibrations are listed in output file (ALLVIBS -- 3N, i.e., rotations and translations included, NORTVIBS -- 3N-6, rotations and translations removed debug -- for program debugging purposes, if set to 1, prints additional information to stderr Added routines for processing GAMESS and ACES2 output files Version 4 (July 1997) Bradley A. Smith (http://pollux.chem.umn.edu/~basmith/, basmith@pollux.chem.umn.edu) - Major rewrite to remove bugs and improve speed and reliability. - Converted syntax from K&R to ANSI C. - Only two passes made through input file. File type and number of atoms determined on first pass. All data read in second pass. - To increase effeciency, changed searching from by word (fscanf("%s") & strcmp()) to by line (fgets() & strncmp()). Examples of data searched for are included in comments. - Dynamic allocation of storage. Number of atoms now limited only by memory. - Data stored in structs for atoms and frequencies improving clarity of data structure and handling. - Debugging statements put inside precompiler directives. - Added support for pallindrome animation Version 4.0.1 (August 1997) Bradley A. Smith (http://pollux.chem.umn.edu/~basmith/, basmith@pollux.chem.umn.edu) - Fixed bug in g94ReadFrequencies(). (Frequency value can start with digit or '-'. Previously would only read frequencies if there were no negative frequencies.) - Correct for when energy not found. - Bug: always wrote vectors for first frequency (Thanks to Peter Freunscht) **********************************************************/ #include #include #include #include #include const char* kXvibsVersion = "4.0.1"; const double angstromPerBohr = 0.529177249; const double TWOPI = 6.28318530717958647688; enum fileType { G92, G94, GAMESS, ACES2, UNKNOWN }; typedef enum fileType FileType; enum animType { LOOP, PALINDROME }; typedef enum animType AnimType; #define DEBUG 0 struct cartesian { double x; double y; double z; }; typedef struct cartesian Cartesian; struct atom { int atomicNumber; double x; double y; double z; }; typedef struct atom Atom; struct freq { double value; Cartesian* coordinates; }; typedef struct freq Freq; FileType typeInput(FILE* file); void writeAtom(FILE* out, Atom* a, Cartesian* v, double scaleVector); double aces2ReadEnergy(FILE* file); int aces2ReadCoordinates(FILE* file, Atom* atoms); int aces2ReadFrequencies(FILE* file, int numAtoms, Freq freqs[]); int aces2CountAtoms(FILE* file); double gamessReadEnergy(FILE* file); int gamessReadCoordinates(FILE* file, Atom* atoms); int gamessReadFrequencies(FILE* file, int numAtoms, Freq freqs[]); int gamessCountAtoms(FILE* file); double g94ReadEnergy(FILE* file); int g94ReadCoordinates(FILE* file, Atom* atoms); int g94ReadFrequencies(FILE* file, int numAtoms, Freq freqs[]); int g94CountAtoms(FILE* file); main(int argc, char* argv[]) { Atom* atoms; Freq* freqs; double energy; int numAtoms; int frames; int freqNumber; int numFreqs; int startFreq; int endFreq; FileType inputType = UNKNOWN; char* baseName; char* fileName; int all; char* pIndex ; FILE* output; FILE* input; const double freqScale = 0.7; const double vectorScale = 2.0; int i; int j; int startFrame; double offset; AnimType animType = LOOP; /* Process command line */ if(argc < 3) { fprintf(stderr, "Insufficient arguments\n"); fprintf(stderr, " xvibs version %s\n", kXvibsVersion); fprintf(stderr, "Usage: xvibs file {all | 1..(3*N-6)} [palindrome]\n"); exit(1); } all = 0; if(argv[2][0] == 'a') { /* all vibrations will be processed */ all = 1; freqNumber = 0; } else freqNumber = atoi(argv[2]) - 1; if(freqNumber < 0) { fprintf(stderr, "Error: frequency number must be a positive integer\n"); exit(6); } if(argc == 4 && argv[3][0] == 'p') { animType = PALINDROME; } /* Set base name for files */ baseName = strdup(argv[1]); if((pIndex = strrchr(baseName, '.')) != NULL ) { *pIndex = '\0'; } /* Open input file */ input = fopen(argv[1],"r"); if(input == NULL) { fprintf(stderr,"Error opening file '%s'\n", argv[1]); exit(2); } /* Get information about the input file format. */ inputType = typeInput(input); if(inputType == UNKNOWN) { fprintf(stderr, "Error: unknown input file type\n"); exit(3); } else if(inputType == G94 || inputType == G92) { numAtoms = g94CountAtoms(input); } else if(inputType == GAMESS) { numAtoms = gamessCountAtoms(input); } else if(inputType == ACES2) { numAtoms = aces2CountAtoms(input); } /* Allocate memory for storage of atomic coordinates and frequencies */ atoms = malloc(sizeof(Atom)*numAtoms); freqs = malloc(sizeof(Freq)*3*numAtoms); for(i=0; i < 3*numAtoms; i++) { if((freqs[i].coordinates = malloc(sizeof(Cartesian)*numAtoms)) == NULL) { fprintf(stderr, "Error: unable to allocate frequency %d (%s)\n", i, strerror(errno)); exit(4); } } if(!(atoms && freqs)) { fprintf(stderr, "Error: unable to allocate memory for %d atoms and %d frequencies\n", numAtoms, 3*numAtoms-6); exit(5); } /* Back to the start of the file */ rewind(input); /* Read input file */ if(inputType == G94 || inputType == G92) { numAtoms = g94ReadCoordinates(input, atoms); energy = g94ReadEnergy(input); if(energy == 0.0) { /* energy not found after searching to end of file; must rewind to find frequencies */ rewind(input); } numFreqs = g94ReadFrequencies(input, numAtoms, freqs); } else if(inputType == GAMESS) { numAtoms = gamessReadCoordinates(input, atoms); energy = gamessReadEnergy(input); if(energy == 0.0) { /* energy not found after searching to end of file; must rewind to find frequencies */ rewind(input); } numFreqs = gamessReadFrequencies(input, numAtoms, freqs); } else if(inputType == ACES2) { numAtoms = aces2ReadCoordinates(input, atoms); energy = aces2ReadEnergy(input); if(energy == 0.0) { /* energy not found after searching to end of file; must rewind to find frequencies */ rewind(input); } numFreqs = aces2ReadFrequencies(input, numAtoms, freqs); } else { fprintf(stderr, "Error reading input file: unknown file type\n"); exit(7); } #if DEBUG fprintf(stderr, "numAtoms=%d\n", numAtoms); for(i=0; i < numAtoms; i++) { fprintf(stderr, "atoms[%d] = %d %10.6f %10.6f %10.6f\n", i, atoms[i].atomicNumber, atoms[i].x, atoms[i].y, atoms[i].z); } fprintf(stderr, "energy = %10.6f\n", energy); fprintf(stderr, "numFreqs=%d\n", numFreqs); for(i=0; i < numFreqs; i++) { fprintf(stderr, "freqs[%d]\t=\t%f\n\t", i, freqs[i].value); for(j=0; j < numAtoms; j++) { fprintf(stderr, "%10.6f %10.6f %10.6f\n\t", freqs[i].coordinates[j].x, freqs[i].coordinates[j].y, freqs[i].coordinates[j].z); } fprintf(stderr, "\n"); } #endif /* Create animation files */ if(numFreqs <= 0) { fprintf(stderr, "Error: no frequencies found\n"); exit(8); } if(all) { startFreq = 0; endFreq = numFreqs; } else { if(freqNumber > numFreqs) { fprintf(stderr, "Error: requested frequency is greater than number of frequencies found, %d\n", numFreqs); exit(9); } startFreq = freqNumber; endFreq = freqNumber+1; } for(freqNumber = startFreq; freqNumber < endFreq ; freqNumber++) { fileName = malloc(sizeof(char)*(strlen(baseName)+8)); sprintf(fileName, "%s.%03d.xyz", baseName, freqNumber+1); output = fopen(fileName, "w"); if(output == NULL) { fprintf(stderr, "Error opening file '%s'\n", fileName); exit(10); } /* Write the coordinates of the equilibrium structure: */ if(animType == LOOP) { fprintf(output, "%d\n", numAtoms); fprintf(output, "* %s, Energy %12.6f\n", argv[1], energy); for(i=0; i < numAtoms; i++) { writeAtom(output, &atoms[i], &freqs[freqNumber].coordinates[i], vectorScale); } } /* Write vibrational structures. */ /* For looping (default), skip j=0 and j=frames because they are equal to the equilibrium geometry. */ startFrame = 1; frames = 20-1; offset = 0.0; /* For palindrome animation, offset starting to furthest point in vibration. */ if(animType == PALINDROME) { startFrame = 0; frames++; offset = M_PI/2.0; } for(j = startFrame; j <= frames; j++) { fprintf(output, "%d\n", numAtoms); fprintf(output, "* Frequency(%d) %10.4f\n", freqNumber+1, freqs[freqNumber].value); for(i=0; i < numAtoms; i++) { /* modify coordinates along normal modes */ Atom a; a.atomicNumber = atoms[i].atomicNumber; a.x = atoms[i].x + freqScale*sin(TWOPI*j/frames+offset)*freqs[freqNumber].coordinates[i].x ; a.y = atoms[i].y + freqScale*sin(TWOPI*j/frames+offset)*freqs[freqNumber].coordinates[i].y ; a.z = atoms[i].z + freqScale*sin(TWOPI*j/frames+offset)*freqs[freqNumber].coordinates[i].z ; writeAtom(output, &a, &freqs[freqNumber].coordinates[i], vectorScale); } } free(fileName); } /* Deallocate memory */ free(baseName); free(atoms); for(i=0; i < 3*numAtoms-6; i++) { free(freqs[i].coordinates); } free(freqs); } void writeAtom(FILE* out, Atom* a, Cartesian* v, double scaleVector) { /* XMol doesn't understand all the periodic table of elements, so everything above Kr is set to X */ static char atomicSymbols[37][3] = { "H ", "He", "Li", "Be", "B ", "C ", "N ", "O ", "F ", "Ne", "Na", "Mg", "Al", "Si", "P ", "S ", "Cl", "Ar", "K ", "Ca", "Sc", "Ti", "V ", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "X " }; int an; /* perhaps v's x, y, and z should be set to zero for too small amplitudes */ an = a->atomicNumber-1; if((an >= 0) && (an < 37)) { fprintf(out,"%s %11.6f %11.6f %11.6f %11.6f %11.6f %11.6f\n", atomicSymbols[an], a->x, a->y, a->z, v->x*scaleVector, v->y*scaleVector, v->z*scaleVector); } else { fprintf(out,"%s %11.6f %11.6f %11.6f %11.6f %11.6f %11.6f\n", atomicSymbols[36], a->x, a->y, a->z, v->x*scaleVector, v->y*scaleVector, v->z*scaleVector); } } FileType typeInput(FILE* file) { FileType type = UNKNOWN; char line[300]; while(fgets(line, 300, file) != NULL) { /* For Gaussian 92 identification seach for "Gaussian 92:". For example, as in the lines: ******************************************** Gaussian 92: SGI-G92/DFT-RevG.2 28-Feb-1994 14-Jul-1997 ******************************************** */ if(strncmp(line, " Gaussian 92:", 13) == 0) { type = G92; break; } /* For Gaussian 94 identification seach for "Gaussian 94:". For example, as in the lines: ************************************************** Gaussian 94: CrayXMP-Unicos-G94RevB.3 30-May-1995 8-Jan-1996 ************************************************** */ if(strncmp(line, " Gaussian 94:", 13) == 0) { type = G94; break; } /* For GAMESS identification seach for "GAMESS". For example, as in the lines: 1 ****************************************************** * GAMESS VERSION = 31 OCT 1996 * * FROM IOWA STATE UNIVERSITY * * M.W.SCHMIDT, K.K.BALDRIDGE, J.A.BOATZ, S.T.ELBERT, * * M.S.GORDON, J.H.JENSEN, S.KOSEKI, N.MATSUNAGA, * * K.A.NGUYEN, S.J.SU, T.L.WINDUS, * * TOGETHER WITH M.DUPUIS, J.A.MONTGOMERY * * J.COMPUT.CHEM. 14, 1347-1363(1993) * *************** CRAY T3D/T3E VERSION ***************** */ else if(strncmp(line, " * GAMESS", 29) == 0) { type=GAMESS; break; } /* For ACES2 identification seach for "* ACES2:". For example, as in the lines: ******************************************************* * ACES2: Advanced Concepts in Electronic Structure II * ******************************************************* */ else if(strncmp(line, " * ACES2:", 19) == 0) { type=ACES2; break; } } return(type); } double gamessReadEnergy(FILE* file) { char line[300]; double energy; int notFound = 1; /* Find energy. For example: TOTAL ENERGY = -284.4340725614 TOTAL POTENTIAL ENERGY = -567.9259211845 */ while(fgets(line, 300, file) != NULL && (notFound = strncmp(line," TOTAL ENERGY =", 30)) != 0) ; if(notFound) { fprintf(stderr, "Error reading GAMESS energy: unable to find TOTAL ENERGY\n"); return 0.0; } sscanf(line, "%*s %*s %*s %lf", &energy); return energy; } int gamessReadCoordinates(FILE* file, Atom* atoms) { char line[300]; int numAtoms; int notFound; double tmpDouble; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: ATOM ATOMIC COORDINATES (BOHR) CHARGE X Y Z C 6.0 -0.6825841446 -2.2557337862 -0.5523839137 C 6.0 1.9677905683 -2.1875543623 -0.1960401740 H 1.0 5.2440255207 0.2405281032 0.0105352224 N 7.0 -3.9086846666 -0.8317610038 1.4705280719 H 1.0 -1.7347344417 -3.9525017430 -1.0103797939 INTERNUCLEAR DISTANCES (ANGS.) ------------------------------ */ while(fgets(line, 300, file) != NULL && (notFound = strncmp(line, " ATOM ATOMIC COORDINATES (BOHR)", 45)) != 0) ; if(notFound) { fprintf(stderr, "Error reading GAMESS coordinates: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read one more header lines. */ if(!(fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading GAMESS coordinates\n"); return 0; } /* Read atomic numbers and count atoms */ while(fscanf(file, "%s %lf %lf %lf %lf", line, &tmpDouble, &atoms[numAtoms].x, &atoms[numAtoms].y, &atoms[numAtoms].z) == 5) { atoms[numAtoms].atomicNumber = (int)tmpDouble; /* Record only real atoms (e.g., skip dummy atoms) */ if(atoms[numAtoms].atomicNumber > 0) { atoms[numAtoms].x *= angstromPerBohr; atoms[numAtoms].y *= angstromPerBohr; atoms[numAtoms].z *= angstromPerBohr; numAtoms++; } } return(numAtoms); } int gamessReadFrequencies(FILE* file, int numAtoms, Freq freqs[]) { char line[300]; char str[100]; int notFound = 1; int numFreqs; int numColumns; char* err; char i1; int i; int j; char* p; char* p2; /* Find normal coordinates. For example: 1 2 3 4 5 6 7 8 9 FREQUENCY: 217.07 I 11.21 10.65 0.48 111.71 119.71 147.44 373.79 487.14 INTENSITY: 0.79509 0.00010 0.00014 0.00115 0.10093 0.04353 0.02010 0.13489 0.24478 1 C X -0.06525937 -0.06932313 0.07834103 -0.00460444 -0.01980564 -0.07329911 -0.02635176 0.02324915 -0.03769840 Y 0.01108711 -0.07550590 -0.06901806 -0.01689686 -0.00306042 0.01949817 0.03203774 -0.03065802 -0.03587336 Z -0.04052354 0.01624196 0.00666195 -0.10169318 0.03720340 0.00728284 -0.10698456 -0.05359112 0.15665786 2 C X -0.05015375 -0.06955566 0.07969405 -0.00441497 -0.00531244 -0.07142766 -0.02144681 0.02126201 -0.01181436 Y -0.00080057 -0.07559116 -0.06803082 -0.01652009 0.00676091 -0.07149885 -0.00148754 -0.00528179 0.00501213 Z 0.05897889 0.01397220 0.00576418 -0.10431512 -0.07503940 0.00055594 -0.12912742 -0.09720340 -0.01513864 3 H X -0.06353590 -0.07031443 0.07869325 -0.00419081 -0.00348353 -0.12860196 -0.03475153 0.04334156 -0.01287901 Y -0.01066747 -0.07479494 -0.06807474 -0.01632475 0.00937945 -0.10622703 -0.00574529 0.01072681 0.00885385 Z 0.06829551 0.01350568 0.00569690 -0.10417082 -0.11264075 0.00235976 -0.22276037 -0.13934044 -0.12084604 4 C X -0.03338173 -0.07013860 0.07845345 -0.00518733 -0.00779069 0.00389958 -0.00207753 -0.01350458 0.00009270 Y -0.02810590 -0.07664076 -0.06810813 -0.01614765 0.00930519 -0.11092367 -0.01811375 0.00955983 -0.00627472 Z 0.06395158 0.01414359 0.00585762 -0.10550101 -0.12532348 -0.00902644 -0.02061296 0.09253504 -0.08576888 TRANS. SAYVETZ X -0.06873026 -6.35147027 7.10097273 -0.50299607 -0.03522640 0.09327256 0.03130830 -0.01901949 0.02163533 Y -0.15436373 -6.96440772 -6.33787366 -1.52043932 0.05770663 -0.09364809 0.11657404 -0.03243428 0.02106756 Z -0.12020741 1.46741752 0.64597405 -9.40445607 0.08815627 -0.00012613 -0.06913014 0.01214535 -0.00326919 TOTAL 0.20736883 9.53925907 9.53990245 9.53983935 0.11109672 0.13217318 0.13909958 0.03951244 0.03037462 ROT. SAYVETZ X -0.61180913 0.23517836 0.15963429 -0.11523672 -3.46880727 -4.57261436 18.72391365 -0.21757856 -0.99021463 Y -1.72682231 0.07039203 0.14402430 0.24705332 23.74657320 1.82363425 2.45544698 -0.77194604 -0.24478613 Z 0.74466282 -0.01595194 0.41284908 0.06033907 3.10802091-29.53230756 -1.84400208 0.47388532 -0.25440341 TOTAL 1.97756123 0.24600481 0.46547875 0.27920539 24.19901148 29.93980016 18.97404822 0.93156235 1.05126893 10 11 12 13 14 15 16 17 18 FREQUENCY: 509.29 606.07 644.38 723.48 801.29 859.63 907.51 941.12 963.88 INTENSITY: 0.39331 0.01822 0.23180 0.43698 0.99749 1.21880 1.53362 1.10749 0.12314 1 C X 0.00951508 0.07419555 0.05148156 -0.01203311 -0.02547399 0.00615577 -0.01079594 0.04049035 -0.09227907 Y -0.06384551 -0.00285285 0.11027733 0.05300815 0.06629486 0.07938637 -0.04210869 0.14486079 -0.02943428 Z -0.06113635 0.03169468 -0.03707645 0.10234522 0.02083381 0.00455239 -0.07654972 -0.00679530 0.04432899 2 C X -0.00553438 0.07457762 0.07069040 0.00065188 -0.04748169 -0.01989750 -0.04324235 -0.01109245 0.04791943 Y -0.03780747 -0.11252936 -0.01163935 0.01910395 0.05990448 -0.01818107 0.06460952 -0.02772412 -0.00051455 Z 0.08132724 -0.02693031 0.05555269 -0.08954265 0.04152869 -0.02146491 -0.01790663 -0.01486294 -0.05978473 3 H X 0.03860447 0.09946674 -0.02788065 -0.05774475 -0.08783155 -0.07366254 -0.05643700 -0.09943890 -0.02048499 Y -0.01803259 -0.09203001 -0.07785475 -0.01676645 0.04656175 -0.06391887 0.04424374 -0.08388983 -0.06907445 Z 0.28689288 -0.13509607 0.14816838 -0.07505464 -0.18413332 0.31338201 0.23765660 0.16710996 0.39173943 4 C X -0.06595468 -0.06157885 0.08993605 0.00894564 0.02823564 -0.03493986 0.03238906 -0.07976203 0.11915560 Y -0.00124967 -0.04869429 -0.04149018 -0.00625735 0.01911195 -0.01192824 0.02030645 -0.02997777 -0.03650293 Z -0.05789594 0.00919090 -0.06189845 0.08398252 0.00426348 -0.05690897 -0.02796632 -0.00943015 -0.03355286 TRANS. SAYVETZ X 0.02692151 0.02853914 -0.03594899 0.00389392 0.03337145 0.00411483 0.01533436 0.02334947 -0.00836761 Y 0.01150354 -0.02217207 0.02677689 0.03509662 0.04309464 0.01568360 0.01805776 0.02066674 -0.00801329 Z 0.00774759 0.00240772 0.00336540 -0.00211745 0.00102919 -0.00791561 -0.01306513 0.00312892 0.01245331 TOTAL 0.03028406 0.03621989 0.04495172 0.03537540 0.05451478 0.01804339 0.02705407 0.03133851 0.01700925 ROT. SAYVETZ X -0.59706936 0.36914336 -0.01310802 -0.14392716 0.02186111 0.21758524 0.00168581 -0.08141964 -0.13161552 Y 0.55791302 -0.04306691 0.10187054 -0.23221808 0.16533779 -0.12633235 0.09130534 -0.03123664 -0.02749576 Z -0.05463445 0.16744376 0.46214627 0.00821074 -0.15478475 -0.01003048 -0.10790792 0.10913322 -0.21735641 TOTAL 0.81898943 0.40762604 0.47342222 0.27332706 0.22753640 0.25180113 0.14136346 0.13969590 0.25558261 REFERENCE ON SAYVETZ CONDITIONS - A. SAYVETZ, J. CHEM. PHYS., 7, 383-389 (1939). */ while((err = fgets(line, 300, file)) != NULL && (notFound = strncmp(line," FREQUENCY:", 16)) != 0) ; if(notFound) { fprintf(stderr, "Error reading GAMESS frequencies: unable to find initial coordinates\n"); return 0; } /* Read frequencies */ numFreqs = 0; while(err != NULL) { /* Count number of columns of data in current set of frequencies */ numColumns = 0; p = strtok(line, " \n\t"); if(p == NULL) break; if(p && strncmp(p, "FREQUENCY:", 10) != 0) break; /* Skip first token: "FREQUENCY:" */ p = strtok(NULL, " \n\t"); if(p && *p != ' ') { if(!isdigit(*p)) break; freqs[numFreqs+numColumns].value = strtod(p, &p2); if(p2 != NULL && *(p2+1) == 'I') { p = strtok(NULL, " \n\t"); freqs[numFreqs+numColumns].value = -freqs[numFreqs+numColumns].value; } numColumns++; while((p = strtok(NULL, " \n\t")) != NULL) { freqs[numFreqs+numColumns].value = strtod(p, &p2); if(p2 != NULL && *(p2+1) == 'I') { p = strtok(NULL, " \n\t"); freqs[numFreqs+numColumns].value = -freqs[numFreqs+numColumns].value; } numColumns++; } } if(numColumns <= 0) { fprintf(stderr, "Error reading GAMESS frequencies: unable to count columns\n"); return 0; } /* Skip to top of vectors */ err = fgets(line, 300, file); err = fgets(line, 300, file); if(err == NULL) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } for(j=0; j < numAtoms; j++) { if(fscanf(file, "%*s %*s %*s") == EOF) { fprintf(stderr, "Error reading GAMESS frequencies: error on first line of atom %d\n", j); return 0; } for(i=0; i < numColumns; i++) { if(fscanf(file, "%lf", &(freqs[numFreqs+i].coordinates[j].x)) == EOF) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } } if(fscanf(file, "%*s") == EOF) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } for(i=0; i < numColumns; i++) { if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[j].y) == EOF) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } } if(fscanf(file, "%*s") == EOF) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } for(i=0; i < numColumns; i++) { if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[j].z) == EOF) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } } } for(i=0; i < 16; i++) { err = fgets(line, 300, file); } if(err == NULL) { fprintf(stderr, "Error reading GAMESS frequencies\n"); return 0; } numFreqs += numColumns; } return numFreqs; } int gamessCountAtoms(FILE* file) { char line[300]; int numAtoms; int notFound; double tmpDouble; int atomicNumber; char* p; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: ATOM ATOMIC COORDINATES (BOHR) CHARGE X Y Z C 6.0 -0.6825841446 -2.2557337862 -0.5523839137 C 6.0 1.9677905683 -2.1875543623 -0.1960401740 H 1.0 5.2440255207 0.2405281032 0.0105352224 N 7.0 -3.9086846666 -0.8317610038 1.4705280719 H 1.0 -1.7347344417 -3.9525017430 -1.0103797939 INTERNUCLEAR DISTANCES (ANGS.) ------------------------------ */ while(fgets(line, 300, file) != NULL && (notFound = strncmp(line, " ATOM ATOMIC COORDINATES (BOHR)", 45)) != 0) ; if(notFound) { fprintf(stderr, "Error counting GAMESS atoms: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read one more header lines. */ if(!(fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error counting GAMESS atoms\n"); return 0; } /* Count atoms */ while(fgets(line, 300, file) != NULL) { /* If line has no tokens (i.e., blank line), end of atoms found */ p = strtok(line, " \n\t"); if(!p || *p == ' ') break; p = strtok(NULL, " \n\t"); if(atof(p) != 0.0) numAtoms++; } return(numAtoms); } double aces2ReadEnergy(FILE* file) { char line[300]; double energy; int notFound = 1; /* Search for SCF energy. For example: E(SCF) = -130.976617544133 a.u. */ while(fgets(line, 300, file) != NULL && (notFound = strncmp(line," E(SCF) =", 37)) != 0) ; if(notFound) { fprintf(stderr, "Error reading ACES2 energy: unable to find SCF energy\n"); return 0.0; } sscanf(line, "%*s %*s %lf", &energy); return energy; } int aces2ReadCoordinates(FILE* file, Atom* atoms) { char line[300]; char s1[30], s2[30], s3[30], s4[30]; int i, j, k, numAtoms, notFound; double coor; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: ----------------------------------------------- Cartesian coordinates corresponding to internal coordinate input (Bohr) ---------------------------------------------------------------- Z-matrix Atomic C o o r d i n a t e s Symbol Number X Y Z ---------------------------------------------------------------- X 0 0.00000000 0.00000000 3.36831426 N 7 0.00000000 0.00000000 1.47858773 C 6 0.00000000 1.28781929 -0.73812957 C 6 0.00000000 -1.28781929 -0.73812957 H 1 0.00000000 3.22348136 -1.48322270 H 1 0.00000000 -3.22348136 -1.48322270 ---------------------------------------------------------------- */ while(fgets(line, 300, file) != NULL && (notFound = strcmp(line," Z-matrix Atomic C o o r d i n a t e s\n")) != 0) ; if(notFound) { fprintf(stderr, "Error reading ACES2 coordinates: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read two more header lines. */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading ACES2 coordinates\n"); return 0; } /* Read atomic numbers and count atoms */ while(fgets(line, 300, file) != NULL) { sscanf(line, "%s %d %lf %lf %lf", line, &atoms[numAtoms].atomicNumber, &atoms[numAtoms].x, &atoms[numAtoms].y, &atoms[numAtoms].z); if(strncmp(line, "--", 2) == 0) { /* End of coordinates reached */ break; } /* Record only real atoms (e.g., skip dummy atoms) */ if(atoms[numAtoms].atomicNumber > 0) { atoms[numAtoms].x *= angstromPerBohr; atoms[numAtoms].y *= angstromPerBohr; atoms[numAtoms].z *= angstromPerBohr; numAtoms++; } } return(numAtoms); } int aces2ReadFrequencies(FILE* file, int numAtoms, Freq freqs[]) { char line[300]; char valueLine[300]; int atomIndex; int notFound = 1; int numFreqs; int numColumns; char* err; char* p; char* p2; int i; /* Find normal coordinates. For example: ---------------------------------------------------------------- Normal Coordinates [Dimensions are Mass**-1/2 Distance] B1 A1 B2 843.48i 927.15 966.97 VIBRATION VIBRATION VIBRATION X Y Z X Y Z X Y Z N 0.1181 0.0000 0.0000 0.0000 0.0000 0.3279 0.0000 0.2361 0.0000 C -0.2535 0.0000 0.0000 0.0000 -0.1155 -0.0033 0.0000 -0.1841 -0.2383 C -0.2535 0.0000 0.0000 0.0000 0.1155 -0.0033 0.0000 -0.1841 0.2383 H 0.6548 0.0000 0.0000 0.0000 -0.2702 -0.5999 0.0000 0.1950 0.5860 H 0.6548 0.0000 0.0000 0.0000 0.2702 -0.5999 0.0000 0.1950 -0.5860 A2 B2 976.13 1142.74 VIBRATION VIBRATION X Y Z X Y Z N 0.0000 0.0000 0.0000 0.0000 0.5594 0.0000 C 0.4152 0.0000 0.0000 0.0000 -0.2642 0.5038 C -0.4152 0.0000 0.0000 0.0000 -0.2642 -0.5038 H -0.5724 0.0000 0.0000 0.0000 -0.1309 0.0527 H 0.5724 0.0000 0.0000 0.0000 -0.1309 -0.0527 Normal modes in internal coordinates --------------------------------------------------------------------------- */ while(fgets(line, 300, file) != NULL && (notFound = strcmp(line," Normal Coordinates \n")) != 0) ; if(notFound) { fprintf(stderr, "Error reading ACES2 coordinates: unable to find initial coordinates\n"); return 0; } /* Normal coordinates found. Read two more header lines. */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading ACES2 coordinates\n"); return 0; } /* Read normal coordinates */ numFreqs = 0; err = fgets(line, 300, file); err = fgets(line, 300, file); while(err != NULL) { /* Count number of columns of data in current set of frequencies */ numColumns = 0; p = strtok(line, " \n\t"); if(p && *p != ' ') { if(!isdigit(*p)) break; freqs[numFreqs+numColumns].value = strtod(p, &p2); if(p2 != NULL && *p2 == 'i') { freqs[numFreqs+numColumns].value = -freqs[numFreqs+numColumns].value; } numColumns++; while((p = strtok(NULL, " \n\t")) != NULL) { freqs[numFreqs+numColumns].value = strtod(p, &p2); if(p2 != NULL && *p2 == 'i') { freqs[numFreqs+numColumns].value = -freqs[numFreqs+numColumns].value; } numColumns++; } } if(numColumns <= 0) { fprintf(stderr, "Error reading ACES2 frequencies: unable to count columns\n"); return 0; } /* Skip to top of vectors */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading ACES2 coordinates\n"); return 0; } for(atomIndex = 0; atomIndex < numAtoms; atomIndex++) { if(fscanf(file, "%*s") == EOF) { fprintf(stderr, "Error reading ACES2 frequencies: error on first line of atom %d\n", atomIndex); return 0; } for(i=0; i < numColumns; i++) { if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].x) == EOF) { fprintf(stderr, "Error reading ACES2 frequencies\n"); return 0; } if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].y) == EOF) { fprintf(stderr, "Error reading ACES2 frequencies\n"); return 0; } if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].z) == EOF) { fprintf(stderr, "Error reading ACES2 frequencies\n"); return 0; } } } numFreqs += numColumns; /* Skip to next set of frequencies */ err = fgets(line, 300, file); err = fgets(line, 300, file); err = fgets(line, 300, file); err = fgets(line, 300, file); } return numFreqs; } int aces2CountAtoms(FILE* file) { char line[300]; int numAtoms, notFound; int atomicNumber; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: ----------------------------------------------- Cartesian coordinates corresponding to internal coordinate input (Bohr) ---------------------------------------------------------------- Z-matrix Atomic C o o r d i n a t e s Symbol Number X Y Z ---------------------------------------------------------------- X 0 0.00000000 0.00000000 3.36831426 N 7 0.00000000 0.00000000 1.47858773 C 6 0.00000000 1.28781929 -0.73812957 C 6 0.00000000 -1.28781929 -0.73812957 H 1 0.00000000 3.22348136 -1.48322270 H 1 0.00000000 -3.22348136 -1.48322270 ---------------------------------------------------------------- */ while(fgets(line, 300, file) != NULL && (notFound = strcmp(line," Z-matrix Atomic C o o r d i n a t e s\n")) != 0) ; if(notFound) { fprintf(stderr, "Error counting ACES2 atoms: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read two more header lines. */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error counting ACES2 atoms\n"); return 0; } /* Read atomic numbers and count atoms */ while(fgets(line, 300, file) != NULL) { sscanf(line, "%s %d %*lf %*lf %*lf", line, &atomicNumber); if(strncmp(line, "--", 2) == 0) { /* End of coordinates reached */ break; } /* Record only real atoms (e.g., skip dummy atoms) */ if(atomicNumber > 0) { numAtoms++; } } return(numAtoms); } double g94ReadEnergy(FILE* file) { char line[300]; double energy; int notFound = 1; /* Search for SCF energy. For example: SCF Done: E(RHF) = -284.418325039 A.U. after 1 cycles */ while(fgets(line, 300, file) != NULL && (notFound = strncmp(line," SCF Done:", 10)) != 0) ; if(notFound) { fprintf(stderr, "Error reading Gaussian94 energy: unable to find SCF energy\n"); return 0.0; } sscanf(line, "%*s %*s %*s %*s %lf", &energy); return energy; } int g94ReadCoordinates(FILE* file, Atom* atoms) { char line[300]; char s1[30], s2[30], s3[30], s4[30]; int i, j, k, numAtoms, notFound; double coor; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: Standard orientation: ---------------------------------------------------------- Center Atomic Coordinates (Angstroms) Number Number X Y Z ---------------------------------------------------------- 1 6 0.000000 0.000000 1.043880 2 6 0.000000 1.215604 0.344031 3 6 0.000000 1.191141 -1.037543 4 6 0.000000 0.000000 -1.744922 5 7 0.000000 0.000000 2.388568 6 1 0.000000 2.146842 0.878573 7 1 0.000000 2.128718 -1.564954 8 1 0.000000 0.000000 -2.818815 9 6 0.000000 -1.215604 0.344031 10 6 0.000000 -1.191141 -1.037543 11 1 0.000000 -2.146842 0.878573 12 1 0.000000 -2.128718 -1.564954 ---------------------------------------------------------- */ while(fgets(line, 300, file) != NULL && (notFound = strcmp(line," Standard orientation:\n")) != 0) ; if(notFound) { fprintf(stderr, "Error reading Gaussian94 coordinates: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read four more header lines. */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading Gaussian94 coordinates\n"); return 0; } /* Read coordinates and count atoms */ while(fgets(line, 300, file) != NULL) { sscanf(line, "%s %d %lf %lf %lf", line, &atoms[numAtoms].atomicNumber, &atoms[numAtoms].x, &atoms[numAtoms].y, &atoms[numAtoms].z); if(strncmp(line, "--", 2) == 0) { /* End of coordinates reached */ break; } /* Record only real atoms (e.g., skip dummy atoms) */ if(atoms[numAtoms].atomicNumber > 0) { numAtoms++; } } return(numAtoms); } int g94ReadFrequencies(FILE* file, int numAtoms, Freq freqs[]) { char line[300]; char valueLine[300]; int atomIndex; int notFound = 1; int numFreqs; int numColumns; char* err; char* p; int i; /* Find normal coordinates. For example: 1 2 3 B1 B2 A2 Frequencies -- 251.6760 306.9127 496.9935 Red. masses -- 5.2279 7.3813 3.0687 Frc consts -- 0.1951 0.4097 0.4466 IR Inten -- 0.1737 4.0142 0.0000 Raman Activ -- 1.5230 1.2659 0.0383 Depolar -- 0.7500 0.7500 0.7500 Atom AN X Y Z X Y Z X Y Z 1 6 -0.12 0.00 0.00 0.00 -0.29 0.00 0.00 0.00 0.00 2 6 -0.27 0.00 0.00 0.00 -0.19 0.11 0.22 0.00 0.00 3 6 -0.01 0.00 0.00 0.00 0.00 0.16 -0.21 0.00 0.00 4 6 0.28 0.00 0.00 0.00 0.07 0.00 0.00 0.00 0.00 4 5 6 A1 B1 B2 Frequencies -- 554.8730 560.1715 671.5923 Red. masses -- 8.4053 2.9412 6.3917 Frc consts -- 1.5247 0.5438 1.6985 IR Inten -- 1.4165 8.4297 0.2472 Raman Activ -- 4.8232 0.0160 3.7362 Depolar -- 0.6340 0.7500 0.7500 Atom AN X Y Z X Y Z X Y Z 1 6 0.00 0.00 0.31 0.30 0.00 0.00 0.00 0.14 0.00 2 6 0.00 -0.21 -0.07 0.01 0.00 0.00 0.00 0.22 0.23 3 6 0.00 -0.16 -0.14 -0.13 0.00 0.00 0.00 -0.24 0.25 4 6 0.00 0.00 -0.37 0.19 0.00 0.00 0.00 -0.15 0.00 ------------------- */ while((err = fgets(line, 300, file)) != NULL && (notFound = strncmp(line," Frequencies -- ", 16)) != 0) ; if(notFound) { fprintf(stderr, "Error reading Gaussian94 coordinates: unable to find initial coordinates\n"); return 0; } /* Read normal coordinates */ numFreqs = 0; while(err != NULL) { /* Count number of columns of data in current set of frequencies */ numColumns = 0; p = strtok(line, " \n\t"); /* Skip first two tokens: "Frequencies", "--" */ p = strtok(NULL, " \n\t"); p = strtok(NULL, " \n\t"); if(p && *p != ' ') { if(isdigit(*p) || *p == '-') { freqs[numFreqs+numColumns].value = atof(p); numColumns++; while((p = strtok(NULL, " \n\t")) != NULL) { freqs[numFreqs+numColumns].value = atof(p); numColumns++; } } } if(numColumns <= 0) { fprintf(stderr, "Error reading Gaussian94 frequencies: unable to count columns\n"); return 0; } /* Skip to top of vectors */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error reading Gaussian94 coordinates\n"); return 0; } for(atomIndex = 0; atomIndex < numAtoms; atomIndex++) { if(fscanf(file, "%*d %*d") == EOF) { fprintf(stderr, "Error reading Gaussian94 frequencies: error on first line of atom %d\n", atomIndex); return 0; } for(i=0; i < numColumns; i++) { if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].x) == EOF) { fprintf(stderr, "Error reading Gaussian94 frequencies\n"); return 0; } if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].y) == EOF) { fprintf(stderr, "Error reading Gaussian94 frequencies\n"); return 0; } if(fscanf(file, "%lf", &freqs[numFreqs+i].coordinates[atomIndex].z) == EOF) { fprintf(stderr, "Error reading Gaussian94 frequencies\n"); return 0; } } } numFreqs += numColumns; /* Skip to next set of frequencies */ while((err = fgets(line, 300, file)) != NULL && strncmp(line," Frequencies -- ", 16) != 0) ; } return numFreqs; } int g94CountAtoms(FILE* file) { char line[300]; int numAtoms, notFound; int atomicNumber; numAtoms = 0; notFound = 1; /* Find initial coordinates. For example: Standard orientation: ---------------------------------------------------------- Center Atomic Coordinates (Angstroms) Number Number X Y Z ---------------------------------------------------------- 1 6 0.000000 0.000000 1.043880 2 6 0.000000 1.215604 0.344031 3 6 0.000000 1.191141 -1.037543 4 6 0.000000 0.000000 -1.744922 5 7 0.000000 0.000000 2.388568 6 1 0.000000 2.146842 0.878573 7 1 0.000000 2.128718 -1.564954 8 1 0.000000 0.000000 -2.818815 9 6 0.000000 -1.215604 0.344031 10 6 0.000000 -1.191141 -1.037543 11 1 0.000000 -2.146842 0.878573 12 1 0.000000 -2.128718 -1.564954 ---------------------------------------------------------- */ while(fgets(line, 300, file) != NULL && (notFound = strcmp(line," Standard orientation:\n")) != 0) ; if(notFound) { fprintf(stderr, "Error counting Gaussian94 atoms: unable to find initial coordinates\n"); return 0; } /* Initial coordinates found. Read four more header lines. */ if(!(fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL && fgets(line, 300, file) != NULL)) { fprintf(stderr, "Error counting Gaussian94 atoms\n"); return 0; } /* Count atoms */ while(fgets(line, 300, file) != NULL) { sscanf(line, "%s %d %*lf %*lf %*lf", line, &atomicNumber); if(strncmp(line, "--", 2) == 0) { /* End of coordinates reached */ break; } /* Record only real atoms (e.g., skip dummy atoms) */ if(atomicNumber > 0) { numAtoms++; } } return(numAtoms); }