Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

gamessplugin.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2006 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 
00010 /* *******************************************************
00011  *
00012  *          G A M E S S     P L U G I N 
00013  *
00014  * This plugin allows VMD to read GAMESS log files
00015  * currently only single point geometries and trajectories
00016  * for optimizations, saddle point runs are supported 
00017  *
00018  * ********************************************************/
00019 
00020 #include "gamessplugin.h"
00021  
00022 
00023 /* 
00024  * pre-processor macro to activate grid code 
00025  */
00026 #ifdef GRID_ACTIVE
00027 #define GRID 1
00028 #else
00029 #define GRID 0
00030 #endif
00031 
00032 /*
00033  * Error reporting macro for use in DEBUG mode
00034  */
00035 #ifdef GAMESS_DEBUG
00036 #define PRINTERR fprintf(stderr, "\n In file %s, line %d: \n %s \n \n", \
00037                             __FILE__, __LINE__, strerror(errno))
00038 #else
00039 #define PRINTERR (void)(0)
00040 #endif
00041 
00042 /*
00043  * Error reporting macro for the multiple fgets calls in
00044  * the code
00045  */
00046 #define ERR_FALSE(x) if ( x == NULL ) return FALSE;
00047 
00048 
00049 /***************************************************************
00050  *
00051  * subroutine doing the initial reading of the GAMESS
00052  * input file
00053  *
00054  * *************************************************************/
00055 static void *open_gamess_read(const char *filename, 
00056                   const char *filetype, int *natoms) {
00057 
00058   FILE *fd;
00059   gamessdata *data;
00060   char mytime[BUFSIZ];
00061 
00062   /* initialize array */
00063   mytime[0] = '\0';
00064 
00065   
00066   /* open the input file */
00067   fd = fopen(filename, "rb");
00068  
00069   /* make sure we were able to load the file properly*/
00070   if (!fd) 
00071   {
00072     PRINTERR;
00073     return NULL;
00074   }
00075 
00076   /* obtain the current time */
00077   get_time(mytime);
00078 
00079   /* print out a short warning message -- we're very alpha */
00080   printf("\n");
00081   printf("     *************************************************\n");
00082   printf("     ***       GAMESSPLUGIN for VMD                ***\n");
00083   printf("     *** %s      ***\n", mytime);
00084   printf("     *** email bugs to vmd@ks.uiuc.edu             ***\n");
00085   printf("     *** v0.4.2 02/20/2007 (c)     Markus Dittrich ***\n");
00086   printf("     *************************************************\n");
00087   printf("\n");
00088 
00089   /* allocate memory for main data structure */
00090   data = (gamessdata *)calloc(1,sizeof(gamessdata));
00091 
00092   /* make sure memory was allocated properly */
00093   if (data == NULL) 
00094   {
00095     PRINTERR;
00096     return NULL;
00097   }
00098 
00099 
00100   /**********************************
00101    * initialize some variables
00102    *********************************/
00103 
00104   /* volumetric */
00105   data->have_volumetric = 0; 
00106 
00107   /* runtyp */
00108   data->runtyp = 0;
00109 
00110   /* initialize the number of atomic shells */
00111   data->num_shells = 0;
00112   
00113   /* have_trajectory flag to 1 */
00114   data->have_trajectory = 1; 
00115 
00116   /* reset trajectory counter */
00117   data->num_traj_points = 0;
00118 
00119   /* presence of wavefunction */
00120   data->got_wavefunction = FALSE;
00121 
00122   /* orbital index of HOMO */
00123   data->homo_index = 0;
00124 
00125   /* flag indicating the presence of
00126    * internal coordinates */
00127   data->have_internals = FALSE;
00128 
00129   /* flag indicating the presence of
00130    * the cartesian Hessian */
00131   data->have_cart_hessian = FALSE;
00132 
00133   /* initialize the number of imaginary 
00134    * modes for HESSIAN type runs */
00135   data->nimag = 0;
00136 
00137   /* initialize internal coordinate counters */
00138   data->nintcoords = 0;
00139   data->nbonds = 0;
00140   data->nangles = 0;
00141   data->ndiheds = 0;
00142   data->nimprops = 0;
00143 
00144   /* initialize the GAMESS version and the PC Gamess flag*/
00145   data->version = 0;
00146   data->have_pcgamess = 0;
00147 
00148   /* initialize the basis set info */
00149   data->ngauss = 0;
00150   data->npfunc = 0;
00151   data->ndfunc = 0;
00152   data->nffunc = 0;
00153   data->diffs  = 0;
00154   data->diffsp = 0;
00155 
00156   /* initialize the number of scfenergies */
00157   data->num_scfenergies = 0;
00158 
00159   /* initialize some of the character arrays */
00160   memset(data->runtyp_string,0,sizeof(data->runtyp_string));
00161   memset(data->basis_string,0,sizeof(data->basis_string));
00162   memset(data->version_string,0,sizeof(data->version_string));
00163   memset(data->scftyp_string,0,sizeof(data->scftyp_string));
00164   memset(data->memory,0,sizeof(data->memory));
00165 
00166   
00167   /***********************************
00168    * done intializing
00169    **********************************/
00170 
00171 
00172   /* store file pointer and filename in gamess
00173    * struct */
00174   data->file = fd;
00175   data->file_name = strdup(filename);
00176 
00177 
00178   /* check if the file is GAMESS format; if yes
00179    * parse it, if no exit */
00180   if ( have_gamess(data) == TRUE ) 
00181   {
00182     /* if we're dealing with an unsupported GAMESS
00183      * version, we better quit */
00184     if ( data->version == 0 )
00185     {
00186       printf("gamessplugin> GAMESS version %s not supported. \n",
00187           data->version_string);
00188       printf("gamessplugin> .... bombing out! Sorry :( \n");
00189       return NULL;
00190     }
00191 
00192     /* get the "static" information from the log file */    
00193     if ( parse_gamess_log_static(data,natoms) == FALSE ) 
00194       return NULL;
00195   }
00196   else 
00197   {
00198     return NULL;
00199   }
00200 
00201 
00202   /* done with the gamess plugin */
00203   rewind(fd);
00204   printf("\n");
00205 
00206 
00207   /* copy pointer also in bogus tcl data pointer */
00208   /* tcl_pointer = data; */
00209 
00210   return data;
00211 }
00212 
00213 
00214 /************************************************************
00215  * 
00216  * subroutine reading in the structure of the molecule
00217  * in the GAMESS output file
00218  *
00219  *************************************************************/
00220 static int read_gamess_structure(void *mydata, int *optflags, 
00221                       molfile_atom_t *atoms) 
00222 {
00223   gamessdata *data = (gamessdata *)mydata;
00224   gamess_temp *temp_atom;
00225   molfile_atom_t *atom;
00226   unsigned int i = 0;
00227  
00228   *optflags = MOLFILE_NOOPTIONS; /* no optional data */
00229 
00230   /* all the information I need has already been read in
00231    * via the initial scan and I simply need to copy 
00232    * everything from the temporary arrays into the 
00233    * proper VMD arrays.
00234    * Since there are no atom names in the GAMESS output
00235    * I use the atom type here --- maybe there is a better
00236    * way to do this !!?? */
00237 
00238   /* get initial pointer for temp arrays */
00239   temp_atom = data->temporary;
00240 
00241   for(i=0;i<data->numatoms;i++)
00242   {
00243     atom=atoms+i;
00244     strncpy(atom->name,temp_atom->type,sizeof(atom->name)); 
00245     strncpy(atom->type,temp_atom->type,sizeof(atom->type));
00246     strncpy(atom->resname,"",sizeof(atom->resname)); 
00247     atom->resid = 1;
00248     atom->charge = temp_atom->charge;
00249     atom->chain[0] = '\0';
00250     atom->segid[0] = '\0';
00251    
00252 
00253     temp_atom++;
00254   }
00255  
00256   return MOLFILE_SUCCESS; 
00257 }
00258 
00259 
00260 /***********************************************************
00261  *
00262  * this function reads in the information for the next
00263  * timestep
00264  *
00265  ***********************************************************/
00266 static int read_next_timestep(void *mydata, int natoms, 
00267     molfile_timestep_t *ts) 
00268 {
00269   gamessdata *data = (gamessdata *)mydata;
00270   gamess_temp *temp_atom;
00271   unsigned int i = 0;
00272 
00273 #ifdef ANIMATE_MODE
00274   mode_data *animated_mode = data->animated_mode;
00275 #endif
00276   
00277   /* Now, if we are not dealing with a trajectory (a single 
00278    * * point conformation is considered one element of a trajectory
00279    */
00280   if (data->have_trajectory == 0) return MOLFILE_ERROR;
00281  
00282 
00283   /* in the case of RUNTYP=ENERGY read data from temp
00284    * arrays and that's it;
00285    * in the case of RUNTYP=OPTIMIZE and SADPOINT just start with
00286    * the first 1NSERCH entry */
00287   if ( data->runtyp == ENERGY ) 
00288   {
00289      /* initialize pointer for temporary arrays */
00290      temp_atom = data->temporary; 
00291  
00292 
00293      /* now copy the initial coordinates from the temporary
00294       * arrays into the VMD ones */
00295      for(i=0;i<natoms;i++)  {
00296 
00297        ts->coords[3*i  ] = temp_atom->x;
00298        ts->coords[3*i+1] = temp_atom->y;
00299        ts->coords[3*i+2] = temp_atom->z; 
00300 
00301        temp_atom++;
00302      }    
00303 
00304      /* Since we are only dealing with a single point which has
00305       * just been read we have to make sure to let VMD know 
00306       * and also register the number of trajectory points as 1 */
00307      data->have_trajectory = 0;
00308 
00309      return MOLFILE_SUCCESS;
00310   }
00311 
00312 #ifndef ANIMATE_MODE
00313   else if ( data->runtyp == HESSIAN ) 
00314   {
00315      /* initialize pointer for temporary arrays */
00316      temp_atom = data->temporary; 
00317  
00318 
00319      /* now copy the initial coordinates from the temporary
00320       * arrays into the VMD ones */
00321      for(i=0;i<natoms;i++)  {
00322 
00323        ts->coords[3*i  ] = temp_atom->x;
00324        ts->coords[3*i+1] = temp_atom->y;
00325        ts->coords[3*i+2] = temp_atom->z; 
00326 
00327        temp_atom++;
00328      }    
00329 
00330      /* Since we are only dealing with a single point which has
00331       * just been read we have to make sure to let VMD know 
00332       * and also register the number of trajectory points as 1 */
00333      data->have_trajectory = 0;
00334 
00335      return MOLFILE_SUCCESS;
00336   }
00337 #endif
00338 
00339 #ifdef ANIMATE_MODE
00340   else if ( data->runtyp == HESSIAN ) 
00341   {
00342     /* read until we run out of frames for the current mode */
00343     if ( animated_mode->current_mode_frame < 
00344               4*animated_mode->mode_num_frames+3 )
00345     {
00346       /* now copy the initial coordinates from the temporary
00347         * arrays into the VMD ones */
00348       for(i=0; i< natoms; i++)  
00349       {
00350         ts->coords[3*i  ] = *(animated_mode->mode_frames +
00351             (animated_mode->current_mode_frame*3*natoms)+3*i);
00352 
00353         ts->coords[3*i+1] = *(animated_mode->mode_frames +
00354             (animated_mode->current_mode_frame*3*natoms)+3*i+1);
00355 
00356         ts->coords[3*i+2] = *(animated_mode->mode_frames +
00357             (animated_mode->current_mode_frame*3*natoms)+3*i+2);
00358       }    
00359 
00360       /* increase the trajectory and mode counter */ 
00361       (animated_mode->current_mode_frame)++;
00362     }
00363     else 
00364     {
00365       return MOLFILE_ERROR;
00366     }
00367 
00368     return MOLFILE_SUCCESS;
00369   }
00370 #endif
00371 
00372   else if ( data->runtyp == OPTIMIZE || data->runtyp == SADPOINT ) 
00373   {
00374     /* call the routine scanning the output file for the
00375      * trajectory */
00376     if ( get_trajectory(data,ts,natoms) == FALSE) {
00377 
00378       /* before we return let's check if we have read
00379        * any trajectory points whatsoever; if not
00380        * this could mean that the file might be
00381        * truncated, and in this case we dump the initial
00382        * coordinate info, such that the user has something
00383        * to look at; */
00384       if ( data->num_traj_points == 0 ) {
00385 
00386         /* initialize pointer for temporary arrays */
00387         temp_atom = data->temporary; 
00388  
00389         
00390         /* now copy the initial coordinates from the temporary
00391         * arrays into the VMD ones */
00392         for(i=0;i<natoms;i++)  {
00393 
00394           ts->coords[3*i  ] = temp_atom->x;
00395           ts->coords[3*i+1] = temp_atom->y;
00396           ts->coords[3*i+2] = temp_atom->z; 
00397 
00398           temp_atom++; }
00399 
00400 
00401         /* make sure we don't continue reading the
00402          * trajectory */
00403         data->have_trajectory = 0;
00404 
00405 
00406         /* that's all we can do */
00407         return MOLFILE_SUCCESS;
00408       }
00409 
00410 
00411       return MOLFILE_ERROR;
00412     }
00413 
00414 
00415     /* increase the trajectory counter */
00416     (data->num_traj_points)++;
00417    
00418 
00419     /* success, it seems :) */
00420     return MOLFILE_SUCCESS;
00421   }
00422 
00423 
00424   /* all other cases should have been rejected allready
00425    * in open_gamess_read;
00426    * but just to make sure we return MOLFILE_ERROR 
00427    * by default */
00428   return MOLFILE_ERROR;
00429 }
00430 
00431 
00432 /*********************************************************
00433  *
00434  * this subroutine makes the volumetric orbital metadata
00435  * available to VMD;
00436  *
00437  ********************************************************/
00438 static int read_orbital_metadata( void *mydata, int *nsets, 
00439                           molfile_volumetric_t **metadata) 
00440 {
00441     gamessdata *data = (gamessdata *)mydata;
00442 
00443     /* first of all we have to test the presence of
00444      * volumetric data; if not set number of volumetric
00445      * data sets to zero and return */
00446 
00447     if ( data->have_volumetric != 1 ) 
00448     {
00449       *nsets = 0;
00450       return MOLFILE_SUCCESS;
00451     }
00452 
00453     /* we only have one set of volumetric data */
00454     *nsets = 1; 
00455 
00456     /* all the necessary data structures have been filled
00457      * in the function get_system_dimensions and we only
00458      * need to copy the pointer. */
00459     *metadata = data->vol;
00460 
00461     return MOLFILE_SUCCESS;
00462 }
00463 
00464 
00465 /**********************************************************
00466  *
00467  * this subroutine makes the volumetric data available 
00468  * to VMD
00469  *
00470  *********************************************************/
00471 static int read_orbital_data( void *mydata, int set, 
00472     float *datablock, float *colorblock) 
00473 {
00474   gamessdata *data = (gamessdata *)mydata;
00475   gamess_temp *temp_data;
00476   molfile_volumetric_t *vol_metadata;
00477   unsigned int i = 0;
00478   int numxyz;
00479 
00480   /* get pointer of temporary data storage */
00481   temp_data = data->temporary; 
00482 
00483   /* get pointer to volumetric metadata */
00484   vol_metadata = data->vol;
00485 
00486   /* move array containing volumetric over to datablock 
00487    * the array contains xsize*ysize*zsize elements */
00488   numxyz = ( vol_metadata->xsize * vol_metadata->ysize * 
00489              vol_metadata->zsize );
00490 
00491   for ( i = 0 ; i < numxyz ; ++i )
00492   {
00493     *(datablock + i) = *(data->orbital_grid+i);
00494   }
00495 
00496   return MOLFILE_SUCCESS;
00497 }
00498 
00499 
00500 /**********************************************************
00501  *
00502  * clean up when done and free all the memory do avoid
00503  * memory leaks
00504  *
00505  **********************************************************/
00506 static void close_gamess_read(void *mydata) {
00507 
00508   gamessdata *data = (gamessdata *)mydata;
00509   fclose(data->file);
00510 
00511   /* free memory */
00512   free(data->temporary);
00513   free(data->basis);
00514   free(data->system_dimensions);
00515   free(data->system_center); 
00516   free(data->orbital_grid);
00517   free(data->basis_counter);
00518   free(data->wave_function);
00519   free(data->orbital_symmetry);
00520   free(data->atomic_shells);
00521   free(data->shell_primitives);
00522   free(data->orbital_energy);
00523   free(data->atomic_number);
00524   free(data->mulliken_charges);
00525   free(data->esp_charges);
00526   free(data->bonds);
00527   free(data->angles);
00528   free(data->dihedrals);
00529   free(data->impropers);
00530   free(data->internal_coordinates);
00531   free(data->bond_force_const);
00532   free(data->angle_force_const);
00533   free(data->dihedral_force_const);
00534   free(data->improper_force_const);
00535   free(data->inthessian);
00536   free(data->carthessian);
00537   free(data->vol);
00538   free(data->scfenergies);
00539   free(data->wavenumbers);
00540   free(data->intensities);
00541   free(data->normal_modes);
00542   
00543   if ( data->runtyp == HESSIAN )
00544   {
00545 #ifdef ANIMATE_MODE
00546     free(data->animated_mode->mode_frames);
00547     free(data->animated_mode);
00548 #endif
00549   }
00550 
00551   free(data);
00552 }
00553 
00554 #if vmdplugin_ABIVERSION > 9
00555 
00556 /*****************************************************
00557  *
00558  * provide VMD with the sizes of the QM related
00559  * data structure arrays that need to be made
00560  * available
00561  *
00562  *****************************************************/
00563 static int read_gamess_metadata(void *mydata, 
00564     molfile_qm_metadata_t *gamess_metadata)
00565 {
00566   gamessdata *data = (gamessdata *)mydata;
00567 
00568 
00569   /* only reserve memory for cartesian/internal 
00570    * hessian if present */
00571   if ( data->runtyp == HESSIAN )
00572   {
00573     gamess_metadata->ncart = (3*data->numatoms);
00574     gamess_metadata->nimag = data->nimag;             
00575    
00576     /* possibly resever memory for internal hessian */
00577     if ( data->have_internals )
00578     {
00579       gamess_metadata->nintcoords = data->nintcoords; 
00580     }
00581     else
00582     {
00583       gamess_metadata->nintcoords = 0;
00584     }
00585   }
00586   else
00587   {
00588     gamess_metadata->ncart = 0;
00589     gamess_metadata->nimag = 0;
00590     gamess_metadata->nintcoords = 0;
00591   }
00592 
00593   
00594   /* fill in orbital data if present */
00595   gamess_metadata->num_basis_funcs = data->num_basis_funcs;
00596   gamess_metadata->orbital_counter = data->orbital_counter;  
00597 
00598 
00599   /* fill in the trajectory information */
00600   gamess_metadata->have_trajectory = data->have_trajectory;
00601   gamess_metadata->num_traj_points = data->num_traj_points;
00602 
00603   return MOLFILE_SUCCESS;
00604 }
00605 
00606 
00607 
00608 /******************************************************
00609  * 
00610  * file the VMD internal QM data structures with their
00611  * respective values
00612  *
00613  ******************************************************/
00614 static int read_gamess_rundata(void *mydata, 
00615     molfile_qm_t *my_qm_data)
00616 {
00617   gamessdata *data = (gamessdata *)mydata;
00618   unsigned int i;
00619   unsigned int ncart;
00620   molfile_qm_hessian_t hessian_data = my_qm_data->hess;
00621   molfile_qm_orbital_t orbital_data = my_qm_data->orb;
00622   molfile_qm_sysinfo_t sys_data = my_qm_data->run;
00623   /* molfile_qm_timestep_t *timestep_data = my_qm_data->timestep; */
00624 
00625 
00626   /* fill in molfile_qm_hessian_t if HESSIAN information
00627    * is available */
00628   if ( data->runtyp == HESSIAN)
00629   {
00630     /* initialize sizes */
00631     ncart = 3*data->numatoms;
00632 
00633     /* hessian/normalmodes in cartesian coordinates */ 
00634     for ( i = 0; i < ncart*ncart; ++i)
00635     {
00636       *(hessian_data.carthessian+i) = *(data->carthessian+i);
00637       *(hessian_data.normalmodes+i) = *(data->normal_modes+i);
00638     }
00639 
00640     /* wavenumbers/intensities */
00641     for ( i = 0; i < ncart; ++i)
00642     {
00643       *(hessian_data.wavenumbers+i) = *(data->wavenumbers+i);
00644       *(hessian_data.intensities+i) = *(data->intensities+i);
00645     }
00646 
00647     /* imaginary modes */
00648     for ( i = 0; i < data->nimag; ++i)
00649     {
00650       *(hessian_data.imag_modes+i) = *(data->nimag_modes+i);
00651     }
00652 
00653     /* internal hessian if present */
00654     if ( data->have_internals )
00655     {
00656       for ( i = 0; i < (data->nintcoords)*(data->nintcoords); ++i)
00657       {
00658         *(hessian_data.inthessian+i) = *(data->inthessian+i);
00659       }
00660     }
00661   }
00662 
00663   
00664   /* fill in molfile_qm_sysinfo_t */
00665   sys_data.runtyp = data->runtyp;
00666   sys_data.nproc = data->nproc;
00667   sys_data.num_gauss_basis_funcs = data->num_gauss_basis_funcs;
00668   sys_data.num_electrons = data->num_electrons;
00669   sys_data.totalcharge = data->totalcharge;
00670   sys_data.multiplicity = data->multiplicity;
00671   sys_data.num_orbitals_A = data->num_orbitals_A;
00672   sys_data.num_orbitals_B = data->num_orbitals_B;
00673   sys_data.scftyp = data->scftyp;
00674   sys_data.ngauss = data->ngauss; 
00675   sys_data.npfunc = data->npfunc;
00676   sys_data.ndfunc = data->ndfunc;
00677   sys_data.nffunc = data->nffunc;
00678   sys_data.diffs = data->diffs;
00679   sys_data.diffsp = data->diffsp;
00680 
00681   for ( i = 0; i < data->numatoms; ++i)
00682   {
00683     *(sys_data.nuc_charge+i) = (data->temporary+i)->charge;
00684   }
00685 
00686   strncpy(sys_data.runtyp_string, data->runtyp_string, 
00687           sizeof(sys_data.runtyp_string));
00688 
00689   strncpy(sys_data.scftyp_string, data->scftyp_string,
00690           sizeof(sys_data.scftyp_string));
00691 
00692   strncpy(sys_data.basis_string, data->basis_string,
00693           sizeof(sys_data.basis_string));
00694   
00695   strncpy(sys_data.memory, data->memory, sizeof(sys_data.memory)); 
00696   strncpy(sys_data.gbasis, data->gbasis, sizeof(sys_data.gbasis));
00697   strncpy(sys_data.runtitle, data->runtitle, sizeof(sys_data.runtitle));
00698   strncpy(sys_data.guess, data->guess, sizeof(sys_data.guess));
00699   strncpy(sys_data.geometry, data->geometry, sizeof(sys_data.geometry));
00700   strncpy(sys_data.version_string, data->version_string,
00701           sizeof(sys_data.version_string));
00702 
00703 
00704   /* fill in molfile_qm_orbital_t */
00705   for ( i = 0; i < data->numatoms; ++i)
00706   {
00707     *(orbital_data.basis_counter+i) = *(data->basis_counter+i);
00708     *(orbital_data.atomic_shells+i) = *(data->atomic_shells+i);
00709   }
00710 
00711   for ( i = 0; i < data->num_shells; ++i)
00712   {
00713     *(orbital_data.shell_primitives+i) = *(data->shell_primitives+i);
00714   }
00715 
00716   for ( i = 0; i < 2*data->num_basis_funcs; ++i)
00717   {
00718     *(orbital_data.basis+i) = *(data->basis+i);
00719   }
00720 
00721   for ( i = 0; i < data->num_basis_funcs; ++i)
00722   {
00723     *(orbital_data.orbital_symmetry+i) = *(data->orbital_symmetry+i);
00724   }
00725 
00726  
00727   /* NOTE: all the quantities in molfile_qm_timestep_t are
00728    * currently only read for the last frame and are therefore
00729    * not available for all timesteps;
00730    * ideally we don't want to the size of molfile_qm_timestep_t
00731    * to be equal to num_traj_points, but rather leave it up
00732    * to the user to select a single point, a certain number
00733    * of points, or all of them. Hence, num_traj_points should
00734    * eventually be replaced by num_available_frames */
00735 
00736   return MOLFILE_SUCCESS;
00737 }
00738 
00739 #endif
00740 
00741 /*************************************************************
00742  *
00743  * registration stuff 
00744  *
00745  **************************************************************/
00746 static molfile_plugin_t plugin;
00747 
00748 
00749 VMDPLUGIN_API int VMDPLUGIN_init(void) {
00750   memset(&plugin, 0, sizeof(molfile_plugin_t));
00751   plugin.abiversion = vmdplugin_ABIVERSION;
00752   plugin.type = MOLFILE_PLUGIN_TYPE;
00753   plugin.name = "gamess";
00754   plugin.prettyname = "GAMESS";
00755   plugin.author = "Markus Dittrich";
00756   plugin.majorv = 0;
00757   plugin.minorv = 6;
00758   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00759   plugin.filename_extension = "log";
00760   plugin.open_file_read = open_gamess_read;
00761   plugin.read_structure = read_gamess_structure;
00762   plugin.read_next_timestep = read_next_timestep;
00763   plugin.close_file_read = close_gamess_read;
00764   plugin.read_volumetric_metadata = read_orbital_metadata;
00765   plugin.read_volumetric_data = read_orbital_data;
00766 
00767 #if vmdplugin_ABIVERSION > 9
00768   plugin.read_qm_metadata = read_gamess_metadata;
00769   plugin.read_qm_rundata = read_gamess_rundata;
00770 #endif
00771 
00772   return VMDPLUGIN_SUCCESS;
00773 }
00774 
00775 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00776   (*cb)(v, (vmdplugin_t *)&plugin);
00777   return VMDPLUGIN_SUCCESS;
00778 }
00779 
00780 VMDPLUGIN_API int VMDPLUGIN_fini(void) {
00781   return VMDPLUGIN_SUCCESS;
00782 }
00783 
00784 
00785 
00786 
00787 /********************************************************
00788  *
00789  * THE NEXT SECTION CONTAINs THE GAMESS OUTPUT FILE
00790  * SPECIFIC SUBROUTINES
00791  *
00792  ********************************************************/
00793 
00794 
00795 
00796 
00797 
00798 /********************************************************
00799  *
00800  * this routine is the main gamess log file
00801  * parser responsible for static, i.e. 
00802  * non-trajectory information 
00803  *
00804  ********************************************************/
00805 static int parse_gamess_log_static(void *mydata, int *natoms) 
00806 {
00807   gamessdata *data = (gamessdata *)mydata;
00808 
00809   /* determine the number of procs and the amount
00810    * of memory requested */
00811   if ( get_proc_mem(data) == FALSE ) return FALSE;
00812 
00813 
00814   /* determine the GBASIS used for the run */
00815   if ( get_gbasis(data) == FALSE ) return FALSE;
00816 
00817 
00818   /* read the run title */
00819   if ( get_runtitle(data) == FALSE ) return FALSE;
00820 
00821 
00822   /* read the contrl group; here we determine the
00823    * RUNTYP and bomb out if we don't support
00824    * it; also read in some controlflow related
00825    * info as well as the COORD type */
00826   if ( check_contrl(data) == FALSE ) return FALSE;
00827 
00828 
00829   /* now call routine get_initial_info to obtain 
00830    * the number of atoms, the atom types, and the
00831    * coordinates, which will be stored in gamess_temp */
00832   if ( get_initial_info(data) == FALSE ) return FALSE;
00833 
00834 
00835   /* provide VMD with the proper number of atoms */
00836   *natoms = data->numatoms;
00837 
00838 
00839   /* read in the number of orbitals, charge, 
00840    * multiplicity, ... */
00841   if ( get_num_orbitals(data) == FALSE ) return FALSE;
00842 
00843 
00844   /* check if the wavefunction and orbital stuff
00845    * is suported for current GBASIS; if not stop
00846    * here and return data pointer */
00847   if ( have_supported_gbasis(data) == FALSE) return TRUE;
00848 
00849 
00850   /* read in the guess options */
00851   if ( get_guess(data) == FALSE ) return FALSE;
00852 
00853   
00854   /* read in the basis set information */
00855   if ( get_basis(data) == FALSE ) return FALSE; 
00856 
00857 
00858   /* read in the final wavefunction; do this only for 
00859    * RUNTYP=ENERGY for now. For the other runs I have to
00860    * put in some more infrastructure to make sure to
00861    * correlate each of the possible many geometries
00862    * during e.g. an optimization run with the correstpoding
00863    * wavefunction 
00864    * for now we also have to restrict reading the wavefunctions
00865    * for singlets only, since otherwise the punched wavefunction
00866    * output differs;
00867    * At least the call to generate orbital grid should
00868    * not be done automagically but rather after a TCL call
00869    * only. 
00870    * NOTE: For PC Gamess we skip this step for now;
00871    * more work to be done here. */
00872   if ( data->runtyp == ENERGY 
00873          && data->num_orbitals_A == data->num_orbitals_B 
00874          && GRID
00875          && data->have_pcgamess != 1 )
00876   {
00877     /* read the wavefunction */
00878     if ( get_wavefunction(data) == FALSE) return FALSE;  
00879 
00880 
00881     /* figure out which one of the orbitals is the HOMO */
00882     if ( find_homo(data) == FALSE) return FALSE; 
00883 
00884  
00885     /* generate the grid containing the volumetric data
00886      * for an orbital */
00887     if( orbital_grid_driver(data) == FALSE ) return FALSE;  
00888 
00889   }
00890 
00891   /* Test print the parsed data in same format as logfile */
00892   /*print_input_data(data);*/
00893 
00894   return TRUE;
00895 }
00896 
00897 #define TORF(x) (x ? "T" : "F")
00898 
00899 static void print_input_data(void *mydata) {
00900   int i, j, k;
00901   int count=0;
00902   gamessdata *data = (gamessdata *)mydata;
00903 
00904   /* QMData *data = (QMData *)mydata; */
00905   printf(" %10s WORDS OF MEMORY AVAILABLE\n", data->memory);
00906   printf("\n");
00907   printf("     BASIS OPTIONS\n");
00908   printf("     -------------\n");
00909   printf("     GBASIS=%8s     IGAUSS=%8i      POLAR=%8s\n", data->gbasis, data->ngauss, "NONE");
00910   printf("     NDFUNC=%8i", data->ndfunc);
00911   printf("     NFFUNC=%8i", data->nffunc);
00912   printf("     DIFFSP=%8s\n", TORF(data->diffsp));
00913   printf("     NPFUNC=%8i", data->npfunc);
00914   printf("      DIFFS=%8s\n", TORF(data->diffs));
00915   printf("\n\n\n");
00916   printf("     RUN TITLE\n");
00917   printf("     ---------\n");
00918   printf(" %s\n", data->runtitle);
00919   printf("\n");
00920   printf(" THE POINT GROUP OF THE MOLECULE IS %s\n", "XXX");
00921   printf(" THE ORDER OF THE PRINCIPAL AXIS IS %5i\n", 0);
00922   printf("\n");
00923   printf(" YOUR FULLY SUBSTITUTED Z-MATRIX IS\n");
00924   printf("\n");
00925   printf(" THE MOMENTS OF INERTIA ARE (AMU-ANGSTROM**2)\n");
00926   printf(" IXX=%10.3f   IYY=%10.3f   IZZ=%10.3f\n", 0.0, 0.0, 0.0);
00927   printf("\n");
00928   printf(" ATOM      ATOMIC                      COORDINATES (BOHR)\n");
00929   printf("           CHARGE         X                   Y                   Z\n");
00930 
00931   for (i=0; i<data->numatoms; i++) {
00932     printf(" %-8s %6.1f", data->temporary[i].type, data->temporary[i].charge);
00933     
00934     printf("%17.10f", ANGS_TO_BOHR*data->temporary[i].x);
00935     printf("%20.10f", ANGS_TO_BOHR*data->temporary[i].y);
00936     printf("%20.10f\n", ANGS_TO_BOHR*data->temporary[i].z);
00937   }
00938   printf("\n");
00939   printf("     ATOMIC BASIS SET\n");
00940   printf("     ----------------\n");
00941   printf(" THE CONTRACTED PRIMITIVE FUNCTIONS HAVE BEEN UNNORMALIZED\n");
00942   printf(" THE CONTRACTED BASIS FUNCTIONS ARE NOW NORMALIZED TO UNITY\n");
00943   printf("\n");
00944   printf("  SHELL TYPE  PRIMITIVE        EXPONENT          CONTRACTION COEFFICIENT(S)\n");
00945   printf("\n");
00946 
00947   for (i=0; i<data->numatoms; i++) {
00948     printf("%-8s\n\n", data->temporary[i].type);
00949     printf("\n");
00950     printf("nshells=%i\n", data->atomic_shells[i]);
00951     for (j=0; j<data->atomic_shells[i]; j++) {
00952       printf("nprim=%i\n", data->shell_primitives[j]);
00953       for (k=0; k<data->shell_primitives[j]; k++) {
00954         printf("%6i   %c %7i %22f", j, data->orbital_symmetry[count], count+1, data->basis[2*count]);
00955         if (data->orbital_symmetry[count] == 'S') {
00956           printf("%22f", data->basis[2*count+1]);
00957         }
00958         printf("\n");
00959         count++;
00960       }
00961       printf("\n");
00962     }
00963   }
00964   printf("\n");
00965   printf(" TOTAL NUMBER OF BASIS SET SHELLS             =%5i\n", data->num_shells);
00966   printf(" NUMBER OF CARTESIAN GAUSSIAN BASIS FUNCTIONS =%5i\n", data->num_gauss_basis_funcs);
00967   printf(" NUMBER OF ELECTRONS                          =%5i\n", data->num_electrons);
00968   printf(" CHARGE OF MOLECULE                           =%5i\n", data->totalcharge);
00969   printf(" SPIN MULTIPLICITY                            =%5i\n", data->multiplicity);
00970   printf(" NUMBER OF OCCUPIED ORBITALS (ALPHA)          =%5i\n", data->num_orbitals_A);
00971   printf(" NUMBER OF OCCUPIED ORBITALS (BETA )          =%5i\n", data->num_orbitals_B);
00972   printf(" TOTAL NUMBER OF ATOMS                        =%5i\n", data->numatoms);
00973   printf("\n");
00974 }
00975 
00976 
00977 /******************************************************
00978  *
00979  * this function extracts the trajectory information
00980  * from the output file
00981  *
00982  * *****************************************************/
00983 static int get_trajectory(void *mydata, molfile_timestep_t *ts,
00984                    int natoms) 
00985 {
00986   gamessdata *data = (gamessdata *)mydata;
00987   char buffer[BUFSIZ];
00988   char word[4][BUFSIZ];
00989   char type[8];
00990   unsigned int i = 0;
00991   float charge,x,y,z;
00992   double scfenergy = 0.0;
00993 
00994   /* zero out the word arrays */
00995   buffer[0] = '\0';
00996   type[0] = '\0';
00997   for ( i = 0; i < 4; ++i) word[i][0] = '\0';
00998 
00999 
01000   /* search for the first coordinate frame during optimization */
01001   ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01002 
01003 
01004   /* at this point we have to distinguish between
01005    * pre="27 JUN 2005 (R2)" and "27 JUN 2005 (R2)"
01006    * versions since the output format for geometry
01007    * optimizations has changed */
01008   if ( data->version == 1)
01009   {
01010      /* scan for the next optimized geometry punched in the 
01011       * logfile */
01012      do 
01013      {
01014        sscanf(buffer,"%s %s",&word[0][0],&word[1][0]); 
01015        ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01016 
01017      } while (strcmp(&word[0][0],"1NSERCH="));
01018   }
01019   else if ( data->version == 2 )
01020   {
01021      /* scan for the next optimized geometry punched in the 
01022       * logfile */
01023      do 
01024      {
01025        sscanf(buffer,"%s %s %s",&word[0][0],&word[1][0],
01026             &word[2][0]); 
01027        ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01028 
01029      } while (strcmp(&word[0][0],"BEGINNING") || 
01030               strcmp(&word[1][0],"GEOMETRY")  ||
01031               strcmp(&word[2][0],"SEARCH"));
01032   }
01033 
01034 
01035   /* next we need to check that we're reading the 
01036    * coordinates of all atoms not only the symmetry
01037    * unique ones in case the point group is not C1 */
01038   ERR_FALSE( fgets(buffer, sizeof(buffer), data->file) )
01039   sscanf(buffer,"%s %s %s", &word[0][0], &word[1][0],
01040       &word[2][0]);
01041 
01042   /* if symmetry unique atoms follow we have to advance
01043    * some more */
01044   if ( !strcmp(&word[2][0],"SYMMETRY") )
01045   {
01046     ERR_FALSE( fgets(buffer, sizeof(buffer), data->file) )
01047    
01048     do 
01049     {
01050       sscanf(buffer,"%s",&word[0][0]); 
01051       ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01052 
01053     } while (strcmp(&word[0][0],"COORDINATES"));
01054 
01055     /* skip next line */
01056     eatline(data->file);
01057   }
01058   else
01059   {
01060     /* skip the next two lines */
01061     eatline(data->file);
01062     eatline(data->file);
01063   }
01064   
01065 
01066   /* read the actual coordinates */
01067   for(i=0;i<natoms;i++) 
01068   {
01069     ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01070     sscanf(buffer,"%s %f %f %f %f",type,&charge,&x,&y,&z);  
01071 
01072     /* store the coordinates */
01073     ts->coords[3*i  ] = x; 
01074     ts->coords[3*i+1] = y;
01075     ts->coords[3*i+2] = z; 
01076   }     
01077 
01078 
01079   /* now we look for the SCF energy of this trajectory 
01080    * point */
01081    do 
01082    {
01083     ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01084     sscanf(buffer,"%s %s %s %lf",&word[0][0],&word[1][0],
01085         &word[2][0],&scfenergy); 
01086  
01087     } while (strcmp(&word[2][0],"ENERGY=") && 
01088              strcmp(&word[1][0],"ENERGY=")); 
01089   
01090   /* allocate more memory for scfenergy array */
01091   data->scfenergies = (double *)realloc(data->scfenergies,
01092         (data->num_traj_points+1)*sizeof(double));
01093 
01094 
01095   /* append current scfenergy to array and increase counter */
01096   *(data->scfenergies+data->num_traj_points) = scfenergy;
01097   data->num_scfenergies++;
01098 
01099 
01100   /* done with this trajectory point */ 
01101   return TRUE;
01102 }
01103 
01104 
01105 
01106 /******************************************************
01107  *
01108  * this function performs an initial file read
01109  * to check its validity and determine the number
01110  * of atoms in the system 
01111  *
01112  * *****************************************************/
01113 static int get_initial_info(void *mydata)
01114 {
01115   gamessdata *data = (gamessdata *)mydata;
01116   gamess_temp *atoms;
01117   char buffer[BUFSIZ];
01118   char word[4][BUFSIZ];
01119   char atname[BUFSIZ];
01120   float charge;
01121   float x,y,z;
01122   unsigned int numatoms;
01123   unsigned int bohr;
01124   unsigned int i,n;
01125   unsigned int have_normal_modes = TRUE;
01126   double scfenergy;
01127   char *status;
01128 
01129   /* initialize buffers */
01130   buffer[0] = '\0';
01131   atname[0] = '\0';
01132   for ( i = 0; i < 4; ++i ) word[i][0] = '\0';
01133  
01134 
01135   /* alocate temporary data structure */
01136   atoms = (gamess_temp *)calloc(MAXQMATOMS,sizeof(gamess_temp));
01137 
01138   /* make sure memory was allocated properly */
01139   if ( atoms == NULL) 
01140   {
01141     PRINTERR; 
01142     return FALSE;
01143   }
01144 
01145 
01146   /* save pointer */
01147   data->temporary = atoms;
01148 
01149 
01150   /* counts the number of atoms in input file */
01151   numatoms=0;  
01152 
01153   /* look for the initial coordinate section 
01154    * NOTE: I also have to check if the coordinates are
01155    * in Angstrom or Bohr and convert them to A in the
01156    * latter case */
01157   rewind(data->file);
01158 
01159   do 
01160   {
01161     ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01162     sscanf(buffer,"%s %s %s %s",&word[0][0],&word[1][0],
01163         &word[2][0],&word[3][0]);
01164 
01165   } while(strcmp(&word[0][0],"ATOM") || 
01166           strcmp(&word[1][0],"ATOMIC"));
01167 
01168   
01169   /* test if coordinate units are Bohr */
01170   bohr = (!strcmp(&word[3][0],"(BOHR)"));
01171 
01172 
01173   /* skip next line */
01174   eatline(data->file);
01175 
01176 
01177   /* now read in the coordinates until an empty line is being
01178    * encoutered */
01179   ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01180   n = sscanf(buffer,"%s %f %f %f %f",atname,&charge,&x,&y,&z);
01181 
01182   /* we expect 5 entries per line */
01183   while( n == 5 ) 
01184   {
01185     strncpy(atoms->type,atname,sizeof(atoms->type));
01186     atoms->charge = charge;
01187 
01188 
01189     /* if coordinates are in Bohr convert them to Angstrom here */
01190     if (bohr) 
01191     {
01192       x = BOHR_TO_ANGS * x;
01193       y = BOHR_TO_ANGS * y;
01194       z = BOHR_TO_ANGS * z;
01195     }
01196 
01197     atoms->x = x;
01198     atoms->y = y;
01199     atoms->z = z; 
01200 
01201 
01202     atoms++;
01203     numatoms++;
01204 
01205     ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01206     n = sscanf(buffer,"%s %f %f %f %f",atname,&charge,&x,&y,&z);
01207   }
01208 
01209   /* store number of atoms in data structure */
01210   data->numatoms = numatoms;
01211 
01212 
01213 
01214   /* save a copy of atom charges in atomic_number array
01215    * of gamessdata */
01216 
01217   /* alocate temporary data structure */
01218   data->atomic_number = (int *)calloc(numatoms,sizeof(int));
01219 
01220   /* make sure memory was allocated properly */
01221   if (data->atomic_number == NULL) 
01222   {
01223     PRINTERR; 
01224     return FALSE;
01225   }
01226 
01227   
01228   /* move data over */ 
01229   for ( n = 0; n < numatoms; n++) 
01230   {
01231     *(data->atomic_number + n) = (int)(data->temporary + n)->charge;
01232   }
01233 
01234 
01235   /* at this point we create an empty scfenergy arrar */
01236   data->scfenergies = (double *)calloc(0,sizeof(double));
01237 
01238 
01239   /* of we are dealing with a single point energy run 
01240    * we read in the final SCF energy and store it;
01241    * TODO: for now also include HESSIAN runs here even though
01242    * this is not completely correct in the case of numerical
01243    * runs*/
01244   if ( (data->runtyp == ENERGY) || (data->runtyp == HESSIAN) )
01245   {
01246     status = fgets(buffer,sizeof(buffer),data->file);
01247      
01248     while ( strcmp(&word[0][0],"FINAL") || 
01249             strcmp(&word[2][0],"ENERGY") ||
01250             strcmp(&word[3][0],"IS"))
01251     {
01252       sscanf(buffer,"%s %s %s %s %lf",&word[0][0],&word[1][0],
01253              &word[2][0],&word[3][0],&scfenergy);
01254 
01255       if ( fgets(buffer,sizeof(buffer),data->file) == NULL) break;
01256     }
01257 
01258     data->scfenergies = (double *)realloc(data->scfenergies,
01259              sizeof(double));
01260     *(data->scfenergies) = scfenergy;
01261     data->num_scfenergies++;
01262   }
01263 
01264 
01265   /* next we check for the Mulliken charges; if they are present
01266    * we set the have_mulliken charge flag, but don't bomb out */
01267 
01268   /* set have_mulliken initially to true */
01269   data->have_mulliken = TRUE;
01270 
01271   do 
01272   {
01273     status = fgets(buffer,sizeof(buffer),data->file);
01274 
01275     /* check for EOF */
01276     if (status == NULL) {
01277      
01278       data->have_mulliken = FALSE;
01279       break;
01280     }
01281 
01282     sscanf(buffer,"%s %s %s %s",&word[0][0],&word[1][0],
01283         &word[2][0],&word[3][0]);
01284 
01285   } while(strcmp(&word[0][0],"TOTAL") || 
01286           strcmp(&word[1][0],"MULLIKEN") ||
01287           strcmp(&word[2][0],"AND")   || 
01288           strcmp(&word[3][0],"LOWDIN") );
01289 
01290 
01291   /* if Mulliken Charges are present read them, if not, rewind
01292    * the file and look for the ESP charges */
01293   if ( data->have_mulliken == TRUE ) 
01294   {
01295     /* reserve memory for dynamically allocated
01296      * Mulliken charge array */
01297     data->mulliken_charges = 
01298       (double *)calloc(numatoms,sizeof(double));
01299 
01300     /* check for success */
01301     if (data->mulliken_charges == NULL) 
01302     {
01303       PRINTERR; 
01304       return FALSE;
01305     }
01306 
01307 
01308     /* skip next line */
01309     eatline(data->file);
01310 
01311     for ( n = 0; n < numatoms; ++n) 
01312     {
01313       /* make sure we don't get nuked by a bad file */
01314       ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01315 
01316       sscanf(buffer,"%s %s %s %lf ",&word[0][0], &word[1][0], 
01317           &word[2][0], (data->mulliken_charges+n));
01318     }
01319   }
01320 
01321   /* no Mulliken charges found; in this case we don't know where
01322    * we are in the file; hence rewind file */
01323   else 
01324   {
01325     rewind(data->file); 
01326   }
01327 
01328 
01329   /* next we check for the ESP charges; if they are present
01330    * we set the have_esp charge flag, but don't bomb out */
01331 
01332   /* set have_esd initially to true */
01333   data->have_esp = TRUE;
01334 
01335   do 
01336   {
01337     status = fgets(buffer,sizeof(buffer),data->file);
01338 
01339     /* check for EOF */
01340     if (status == NULL) {
01341      
01342       data->have_esp = FALSE;
01343       break;
01344     }
01345 
01346     sscanf(buffer,"%s %s %s",&word[0][0],&word[1][0],&word[2][0]);
01347 
01348   } while(strcmp(&word[0][0],"ATOM") || 
01349           strcmp(&word[1][0],"CHARGE") ||
01350           strcmp(&word[2][0],"E.S.D.") );
01351 
01352 
01353   /* if ESP Charges are present read them, if not, rewind
01354    * the file and return */
01355   if ( data->have_esp == TRUE ) 
01356   {
01357     /* reserve memory for dynamically allocated
01358      * Mulliken charge array */
01359     data->esp_charges = 
01360       (double *)calloc(numatoms,sizeof(double));
01361 
01362     /* check for success */
01363     if (data->esp_charges == NULL) 
01364     {
01365       PRINTERR; 
01366       return FALSE;
01367     }
01368 
01369 
01370     /* skip next line */
01371     eatline(data->file);
01372 
01373     for ( n = 0; n < numatoms; ++n) {
01374 
01375       /* make sure we don't get nuked by a bad file */
01376       ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01377       sscanf(buffer,"%s %lf ",&word[0][0], (data->esp_charges+n));
01378     }
01379   }
01380 
01381   /* no ESP charges found; in this case we don't know where
01382    * we are in the file; hence rewind file */
01383   else 
01384   {
01385     rewind(data->file); 
01386   }
01387 
01388 
01389   /* short message */ 
01390   printf("gamessplugin> Detected %d atoms in the input file. \n",
01391           data->numatoms);
01392 
01393 
01394   if ( data->runtyp == HESSIAN ) 
01395   {
01396 
01397 #ifdef ANIMATE_MODE
01398     initialize_animated_mode(data);
01399 #endif
01400 
01401     /* try reading the hessian matrix in internal and
01402      * cartesian coordinates as well as the internal
01403      * coordinates together with their associated
01404      * force constants */
01405     if ( get_int_coords(data) == TRUE ) 
01406     {
01407       data->have_internals = TRUE;
01408     }
01409     else 
01410     {
01411       printf("gamessplugin> \n");
01412       printf("gamessplugin> Could not determine the internal \n");
01413       printf("gamessplugin> coordinate and Hessian info!! \n");
01414       printf("gamessplugin> \n");
01415     }
01416     
01417  
01418     if ( get_cart_hessian(data) == TRUE ) 
01419     {
01420       data->have_cart_hessian = TRUE;
01421     }
01422     else 
01423     {
01424       printf("gamessplugin> \n");
01425       printf("gamessplugin> Could not determine the cartesian \n");
01426       printf("gamessplugin> Hessian matrix!! \n");
01427       printf("gamessplugin> \n");
01428     }
01429 
01430 
01431     /* read the wavenumbers, intensities of the normal modes 
01432      * as well as the modes themselves */
01433     if ( get_normal_modes(data) == FALSE ) 
01434     {
01435       printf("gamessplugin> \n");
01436       printf("gamessplugin> Could not scan the normal modes,\n");
01437       printf("gamessplugin> \n");
01438 
01439       have_normal_modes = FALSE;
01440     }
01441 
01442 #ifdef ANIMATE_MODE
01443     /* generate an animated trajectory for mode i */ 
01444     if (data->have_cart_hessian && have_normal_modes) 
01445     {
01446       if ( animate_normal_mode(data, 62) == FALSE )
01447       {
01448         printf("gamessplugin> \n");
01449         printf("gamessplugin> Error generating animated normal mode");
01450         printf("gamessplugin> \n \n");
01451       }
01452     }
01453 #endif
01454 
01455   }
01456 
01457   /* done with this one */
01458   return TRUE; 
01459 }
01460 
01461 
01462 
01463 /******************************************************
01464  *
01465  * this function generates animated frames for normal
01466  * mode mode_to_animate
01467  *
01468  * *****************************************************/
01469 static int initialize_animated_mode(void *mydata)
01470 {
01471   gamessdata *data = (gamessdata *)mydata;
01472   mode_data *animated_mode;
01473 
01474   /* allocate memory for a mode_data struct */
01475   animated_mode = (mode_data *)calloc(1,sizeof(mode_data)); 
01476 
01477   if ( animated_mode == NULL )
01478   {
01479     PRINTERR;
01480     return FALSE;
01481   }
01482 
01483   /* save pointer in gamessdata struct */
01484   data->animated_mode = animated_mode;
01485 
01486   /* set the number of frames per animated mode */
01487   animated_mode->mode_num_frames = 25;
01488 
01489   /* initialize the animated mode tracker */
01490   animated_mode->current_mode_frame = 0;
01491 
01492   /* set the scaling factor for the animated mode */
01493   animated_mode->mode_scaling = 0.01;
01494 
01495   /* reserve memory for animated mode trajectory */
01496   animated_mode->mode_frames = (double *)calloc((4 *
01497       animated_mode->mode_num_frames+3)*data->numatoms*3, 
01498       sizeof(double));
01499 
01500   if ( animated_mode->mode_frames == NULL )
01501   {
01502     PRINTERR;
01503     return FALSE;
01504   }
01505 
01506   return TRUE;
01507 }
01508 
01509 
01510 
01511 /************************************************************
01512  *
01513  * this function animates a given normal mode by means of
01514  * generating mod_num_frames frames away from the equilibrium
01515  * structure in a direction given by the hessiane 
01516  *
01517  ************************************************************/
01518 static int animate_normal_mode(void *mydata, unsigned int mode)
01519 {
01520   gamessdata *data = (gamessdata *)mydata;
01521   mode_data *animated_mode = data->animated_mode;
01522   double *normal_modes = data->normal_modes;
01523   double scale = animated_mode->mode_scaling;
01524   unsigned int i = 0, k = 0; 
01525   int l = 0, m = 0;
01526   unsigned int natoms = data->numatoms;
01527   unsigned int num_frames = animated_mode->mode_num_frames;
01528 
01529   /* first sweep to max of interval */
01530   for ( k = 0; k < num_frames+1; ++k)
01531   {
01532     for ( i = 0; i < natoms; ++i)
01533     {
01534       *(animated_mode->mode_frames+(k*natoms*3)+(3*i)) = 
01535           (data->temporary+i)->x * (1+( k*scale * 
01536           (*(normal_modes+(mode*natoms*3)+(3*i)))));
01537 
01538       *(animated_mode->mode_frames+(k*natoms*3)+(3*i+1)) = 
01539           (data->temporary+i)->y * (1+( k*scale * 
01540           (*(normal_modes+(mode*natoms*3)+(3*i+1)))));
01541 
01542       *(animated_mode->mode_frames+(k*natoms*3)+(3*i+2)) = 
01543           (data->temporary+i)->z * (1+( k*scale * 
01544           (*(normal_modes+(mode*natoms*3)+(3*i+2)))));
01545     }
01546   }
01547 
01548 
01549   /* second sweep all the way back to min of interval */
01550   for ( l = 0; l < 2*num_frames+1; ++l)
01551   {
01552     for ( i = 0; i < natoms; ++i)
01553     {
01554       *(animated_mode->mode_frames+((l+k)*natoms*3)+(3*i)) = 
01555           (data->temporary+i)->x * (1+((int)(num_frames-l)*scale * 
01556           (*(normal_modes+(mode*natoms*3)+(3*i)))));
01557 
01558       *(animated_mode->mode_frames+((l+k)*natoms*3)+(3*i+1)) = 
01559           (data->temporary+i)->y * (1+((int)(num_frames-l)*scale * 
01560           (*(normal_modes+(mode*natoms*3)+(3*i+1)))));
01561 
01562       *(animated_mode->mode_frames+((l+k)*natoms*3)+(3*i+2)) = 
01563           (data->temporary+i)->z * (1+((int)(num_frames-l)*scale * 
01564           (*(normal_modes+(mode*natoms*3)+(3*i+2)))));
01565     }
01566   }
01567 
01568 
01569   /* third sweep back to the native starting structure */
01570   for ( m = 0; m < num_frames+1; ++m)
01571   {
01572     for ( i = 0; i < natoms; ++i)
01573     {
01574       *(animated_mode->mode_frames+((l+k+m)*natoms*3)+(3*i)) = 
01575           (data->temporary+i)->x * (1+((int)(m-num_frames)*scale * 
01576           (*(normal_modes+(mode*natoms*3)+(3*i)))));
01577 
01578       *(animated_mode->mode_frames+((l+k+m)*natoms*3)+(3*i+1)) = 
01579           (data->temporary+i)->y * (1+((int)(m-num_frames)*scale * 
01580           (*(normal_modes+(mode*natoms*3)+(3*i+1)))));
01581 
01582       *(animated_mode->mode_frames+((l+k+m)*natoms*3)+(3*i+2)) = 
01583           (data->temporary+i)->z * (1+((int)(m-num_frames)*scale * 
01584           (*(normal_modes+(mode*natoms*3)+(3*i+2)))));
01585     }
01586   }
01587 
01588   /* short message */
01589   printf("gamessplugin> Successfully animated mode %d \n", mode);
01590 
01591   return TRUE;
01592 }
01593 
01594 
01595 
01596 /***********************************************************
01597  *
01598  * this function reads in the wavenumbers and intensities of
01599  * the normal modes
01600  *
01601  * *********************************************************/
01602 static int get_normal_modes(void *mydata)
01603 {
01604   gamessdata *data = (gamessdata *)mydata;
01605   char word[4][BUFSIZ];
01606   char buffer[BUFSIZ];
01607   unsigned int i = 0, k = 0, j = 0;
01608   unsigned int remaining_columns;
01609   double entry[6]; 
01610   char separator;
01611   char *item;
01612   unsigned int counter;
01613 
01614 
01615   /* initialize arrays */
01616   buffer[0] = '\0';
01617   memset(entry, 0, sizeof(entry));
01618   for ( i = 0; i < 4; ++i) word[i][0] = '\0';
01619 
01620     
01621   /* reserve memory for dynamically allocated data
01622    * arrays */
01623   item = (char *)calloc(BUFSIZ,sizeof(char));
01624 
01625   if ( item == NULL )
01626   {
01627     PRINTERR;
01628     return FALSE;
01629   }
01630 
01631 
01632   data->wavenumbers = 
01633     (double *)calloc(data->numatoms*3,sizeof(double));
01634 
01635   if ( data->wavenumbers == NULL ) 
01636   {
01637     PRINTERR;
01638     return FALSE;
01639   }
01640 
01641 
01642   data->intensities = 
01643     (double *)calloc(data->numatoms*3,sizeof(double));
01644 
01645   if ( data->intensities == NULL ) 
01646   {
01647     PRINTERR;
01648     return FALSE;
01649   }
01650 
01651 
01652   data->normal_modes = 
01653     (double *)calloc((data->numatoms*3)*(data->numatoms*3),
01654                      sizeof(double));
01655 
01656   if ( data->normal_modes == NULL ) 
01657   {
01658     PRINTERR;
01659     return FALSE;
01660   }
01661 
01662 
01663   /* look for FREQUENCYs and IR INTENSITIES */
01664   for ( i = 0; i < (unsigned int)(data->numatoms*3/5); ++i) 
01665   {
01666     do 
01667     {
01668       ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01669       sscanf(buffer,"%s ",&word[0][0]);
01670 
01671     } while(strcmp(&word[0][0],"FREQUENCY:"));
01672 
01673 
01674     /* scan the frequencies; 
01675      * this requires some care since there might
01676      * be imaginary modes present which leads to
01677      * an additional char per imaginary mode per
01678      * line */
01679 
01680     /* check for imaginary modes */
01681     if ( strchr(buffer,'I') != NULL ) 
01682     {
01683       /* initialize */
01684       separator = ' ';
01685       counter = 0;
01686 
01687       /* read all line elements into individual strings */
01688 
01689       /* skip first entry "FREQUENCY" */
01690       item = strtok(buffer,&separator);
01691       
01692       /* start going through the string */
01693       while ( (item = strtok(NULL,&separator)) != NULL ) 
01694       {
01695         /* check if item is 'I'; if yes, mark previous mode
01696          * as imaginary; otherwise save the mode */
01697         if ( *item == 'I' ) 
01698         {
01699           data->nimag++;
01700         }
01701         else 
01702         {
01703           /* save only the first 5 modes - there NEVER should
01704            * be more in any case, but just to make sure
01705            * we don't overrun the array */
01706           if ( counter < 5 ) 
01707           {
01708             *(data->wavenumbers+(i*5)+counter) = atof(item);
01709             counter++;
01710           }
01711         }
01712       } 
01713     }
01714 
01715 
01716     /* no imaginary mode, reading is straightforward */
01717     else 
01718     {
01719       sscanf(buffer,"%s %lf %lf %lf %lf %lf",&word[0][0],
01720         &entry[0],&entry[1],&entry[2],&entry[3],&entry[4]); 
01721     
01722       /* save 'em */
01723       for ( k = 0; k < 5; ++k) 
01724       {
01725         *(data->wavenumbers+(i*5)+k) = entry[k]; 
01726       }
01727     }
01728 
01729 
01730     /* skip next line */
01731     eatline(data->file);
01732 
01733 
01734     /* next line contains the IR INTENSITIES */
01735     ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01736 
01737     /* scan the IR INTENSITIES */
01738     sscanf(buffer,"%s %s %lf %lf %lf %lf %lf",&word[0][0],&word[1][0],
01739         &entry[0],&entry[1],&entry[2],&entry[3],&entry[4]);
01740  
01741 
01742     /* save 'em */
01743     for ( k = 0; k < 5; ++k) 
01744     {
01745       *(data->intensities+(i*5)+k) = entry[k]; 
01746     }
01747 
01748     /* skip the next line */
01749     eatline(data->file);
01750 
01751     /* read the following five modes */
01752     for ( k = 0; k < data->numatoms; ++k)
01753     {
01754       /* x */
01755       ERR_FALSE( fgets(buffer,sizeof(buffer),data->file) )
01756       sscanf(buffer,"%s %s %s %lf %lf %lf %lf %lf",&word[0][0], 
01757           &word[1][0], &word[2][0], &entry[0], &entry[1], &entry[2],
01758           &entry[3], &entry[4]);
01759 
01760       /* store 'em */
01761       for ( j = 0; j < 5; ++j)
01762       {
01763         *(data->normal_modes+(3*k)+((i*5+j)*3*data->numatoms)) = 
01764             entry[j];
01765       }
01766 
01767 
01768       /* y */
01769       ERR_FALSE( fgets(buffer,sizeof