Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

MolFilePlugin.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: MolFilePlugin.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.175 $      $Date: 2012/02/01 00:11:26 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   VMD interface to 'molfile' plugins.  Molfile plugins read coordinate
00019  *   files, structure files, volumetric data, and graphics data.  The data
00020  *   is loaded into a new or potentially preexisting molecule in VMD.
00021  *   Some molefile plugins can also export data from VMD to files.
00022  * 
00023  * LICENSE:
00024  *   UIUC Open Source License
00025  *   http://www.ks.uiuc.edu/Research/vmd/plugins/pluginlicense.html
00026  * 
00027  ***************************************************************************/
00028 
00029 #include <stdio.h>
00030 
00031 #include "MolFilePlugin.h"
00032 #include "Molecule.h"
00033 #include "AtomSel.h"
00034 #include "Timestep.h"
00035 #include "Inform.h"
00036 #include "Scene.h"
00037 #include "molfile_plugin.h"
00038 #include "PeriodicTable.h"
00039 #include "VolumetricData.h"
00040 #include "MoleculeGraphics.h"
00041 #include "QMData.h"
00042 #include "QMTimestep.h"
00043 
00044 #if defined(VMDTKCON)
00045 #include "vmdconsole.h"
00046 #endif
00047 
00048 #define MINSIZEOF(a, b) \
00049         ((sizeof(a) < sizeof(b)) ? sizeof(a) : sizeof(b))
00050 
00051 #define SAFESTRNCPY(a, b) \
00052         (strncpy(a, b, MINSIZEOF(a, b)))
00053 
00054 MolFilePlugin::MolFilePlugin(vmdplugin_t *p)
00055 : plugin((molfile_plugin_t *)p) {
00056   rv = wv = NULL; 
00057   numatoms = 0;
00058   _filename = NULL;
00059 #if vmdplugin_ABIVERSION > 13
00060   qm_data = NULL;
00061 #if defined(VMDTKCON)
00062    plugin->cons_fputs = &vmdcon_fputs;
00063 #else
00064    plugin->cons_fputs = NULL;
00065 #endif
00066 #endif
00067 }
00068 
00069 MolFilePlugin::~MolFilePlugin() {
00070   close();
00071   delete [] _filename;
00072 }
00073 
00074 int MolFilePlugin::read_structure(Molecule *m, int filebonds, int autobonds) {
00075   if (!rv) return MOLFILE_ERROR; 
00076   if (!can_read_structure()) return MOLFILE_ERROR;
00077   if (!m->init_atoms(numatoms)) return MOLFILE_ERROR;
00078 
00079   molfile_atom_t *atoms = 
00080     (molfile_atom_t *) calloc(1, numatoms*sizeof(molfile_atom_t));
00081 
00082   int rc, i;
00083   int optflags = MOLFILE_BADOPTIONS; /* plugin must reset this correctly */
00084   if ((rc = plugin->read_structure(rv, &optflags, atoms))) {
00085     free(atoms);
00086     return rc; // propagate error to caller
00087   }
00088   if (optflags == MOLFILE_BADOPTIONS) {
00089     free(atoms);
00090     msgErr << "MolFilePlugin: plugin didn't initialize optional data flags" << sendmsg;
00091     msgErr << "MolFilePlugin: file load aborted" << sendmsg;
00092     return MOLFILE_ERROR; /* abort load, data can't be trusted */
00093   }
00094 
00095 
00096   float *charge = m->charge();
00097   float *mass = m->mass();
00098   float *radius = m->radius();
00099   float *beta = m->beta();
00100   float *occupancy = m->occupancy();
00101 
00102   // set molecule dataset flags
00103   if (optflags & MOLFILE_INSERTION)
00104     m->set_dataset_flag(BaseMolecule::INSERTION);
00105   if (optflags & MOLFILE_OCCUPANCY)
00106     m->set_dataset_flag(BaseMolecule::OCCUPANCY);
00107   if (optflags & MOLFILE_BFACTOR)
00108     m->set_dataset_flag(BaseMolecule::BFACTOR);
00109   if (optflags & MOLFILE_MASS)
00110     m->set_dataset_flag(BaseMolecule::MASS);
00111   if (optflags & MOLFILE_CHARGE)
00112     m->set_dataset_flag(BaseMolecule::CHARGE);
00113   if (optflags & MOLFILE_RADIUS)
00114     m->set_dataset_flag(BaseMolecule::RADIUS);
00115   if (optflags & MOLFILE_ALTLOC)
00116     m->set_dataset_flag(BaseMolecule::ALTLOC);
00117   if (optflags & MOLFILE_ATOMICNUMBER)
00118     m->set_dataset_flag(BaseMolecule::ATOMICNUMBER);
00119 
00120   // Force min/max atom radii to be updated since we've loaded new data
00121   if (optflags & MOLFILE_RADIUS)
00122     m->set_radii_changed();
00123 
00124   for (i=0; i<numatoms; i++) {
00125     molfile_atom_t &atom = atoms[i];
00126     int atomicnumber = (optflags & MOLFILE_ATOMICNUMBER) ? 
00127       atom.atomicnumber : -1;
00128     charge[i] = (optflags & MOLFILE_CHARGE) ?
00129       atom.charge : m->default_charge(atom.name);
00130  
00131     // If we're given an explicit mass value, use it.
00132     // Failing that, try doing a periodic table lookup if we have
00133     // a valid atomicnumber.  If that fails also, then we use a crude
00134     // guess based on the atom name string. 
00135     mass[i] = (optflags & MOLFILE_MASS) ?
00136       atom.mass : ((atomicnumber > 0) ?
00137         get_pte_mass(atomicnumber) : m->default_mass(atom.name));
00138 
00139     // If we're given an explicit VDW radius value, use it.
00140     // Failing that, try doing a periodic table lookup if we have
00141     // a valid atomicnumber.  If that fails also, then we use a crude
00142     // guess based on the atom name string. 
00143     radius[i] = (optflags & MOLFILE_RADIUS) ?
00144       atom.radius : ((atomicnumber > 0) ?
00145         get_pte_vdw_radius(atomicnumber) : m->default_radius(atom.name));
00146 
00147     beta[i] = (optflags & MOLFILE_BFACTOR) ?
00148       atom.bfactor : m->default_beta();
00149     occupancy[i] = (optflags & MOLFILE_OCCUPANCY) ?
00150       atom.occupancy : m->default_occup();
00151     const char *insertion = (optflags & MOLFILE_INSERTION) ? 
00152       atom.insertion : " ";
00153     const char *altloc = (optflags & MOLFILE_ALTLOC) ?
00154       atom.altloc : "";
00155     if (0 > m->add_atom(atom.name, atom.type, atomicnumber, 
00156                         atom.resname, atom.resid, 
00157                         atom.chain, atom.segid, (char *)insertion, altloc)) {
00158       // if an error occured while adding an atom, we should delete
00159       // the offending molecule since the data is presumably inconsistent,
00160       // or at least not representative of what we tried to load
00161       msgErr << "MolFilePlugin: file load aborted" << sendmsg;
00162       free(atoms);
00163       return MOLFILE_ERROR; // abort load, data can't be trusted
00164     }
00165   }
00166   free(atoms);
00167 
00168   if (filebonds && can_read_bonds()) {
00169     int nbonds, *from, *to, nbondtypes, *bondtype;
00170     float *bondorder;
00171     char **bondtypename;
00172 
00173     // must explicitly set these since they may are otherwise only 
00174     // initialized by the read_bonds() call in the new ABI
00175     nbondtypes = 0;
00176     bondtype = NULL;
00177     bondtypename = NULL;
00178  
00179 #if vmdplugin_ABIVERSION >= 15
00180     if (plugin->read_bonds(rv, &nbonds, &from, &to, &bondorder, &bondtype, 
00181                            &nbondtypes, &bondtypename)) 
00182 #else
00183     if (plugin->read_bonds(rv, &nbonds, &from, &to, &bondorder)) 
00184 #endif
00185     {
00186       
00187       msgErr << "Error reading bond information." << sendmsg;
00188       if (autobonds)
00189         m->find_bonds_from_timestep();
00190     } else {
00191       // if we didn't get an error, but the plugin didn't define bonds
00192       // for some reason (i.e. no usable PDB CONECT records found)
00193       // fall back to automatic bond search
00194       if (nbonds == 0 && from == NULL && to == NULL) {
00195         if (autobonds)
00196           m->find_bonds_from_timestep();
00197       } else if (nbonds > 0) {
00198         // insert bondtype names into our pool of names. this will preserve 
00199         // the indexing if no other names do already exist.
00200         if (bondtypename != NULL)
00201           for (i=0; i < nbondtypes; i++)
00202             m->bondTypeNames.add_name(bondtypename[i], i);
00203 
00204         // If the bonds provided by the plugin were only the for
00205         // non-standard residues (i.e. PDB CONECT records) then we'll
00206         // also do our regular bond search, combining all together, but 
00207         // preventing duplicates
00208         if (optflags & MOLFILE_BONDSSPECIAL) {
00209           if (autobonds) {
00210             m->find_unique_bonds_from_timestep(); // checking for duplicates
00211           }
00212 
00213           // indicate what kind of data will be available.
00214           m->set_dataset_flag(BaseMolecule::BONDS);
00215           if (bondorder != NULL) 
00216             m->set_dataset_flag(BaseMolecule::BONDORDERS);
00217           if (bondtype  != NULL) 
00218             m->set_dataset_flag(BaseMolecule::BONDTYPES);
00219           
00220           // Now add in all of the special bonds provided by the plugin
00221           for (i=0; i<nbonds; i++) {
00222             float bo =  1;
00223             int   bt = -1;
00224             if (bondorder != NULL) 
00225               bo = bondorder[i];
00226             if (bondtype  != NULL) {
00227               if (bondtypename != NULL) {
00228                 bt = m->bondTypeNames.typecode(bondtypename[bondtype[i]]);
00229               } else {
00230                 bt = bondtype[i];
00231               }
00232             }
00233             m->add_bond_dupcheck(from[i]-1, to[i]-1, bo, bt); 
00234           }
00235         } else {
00236 
00237           // indicate what kind of data will be available...
00238           m->set_dataset_flag(BaseMolecule::BONDS);
00239           if (bondorder != NULL) 
00240             m->set_dataset_flag(BaseMolecule::BONDORDERS);
00241           if (bondtype  != NULL) 
00242             m->set_dataset_flag(BaseMolecule::BONDTYPES);
00243 
00244           // ...and add the bonds.
00245           for (i=0; i<nbonds; i++) {
00246             float bo =  1;
00247             int   bt = -1;
00248             if (bondorder != NULL) bo = bondorder[i];
00249             if (bondtype  != NULL) bt = bondtype[i];
00250             m->add_bond(from[i]-1, to[i]-1, bo, bt); 
00251           }
00252         }
00253       }
00254     }
00255   } else {
00256     if (autobonds)
00257       m->find_bonds_from_timestep();
00258   }
00259 
00260   // if the plugin can read angles, dihedrals, impropers, cross-terms, 
00261   // do it here...
00262 #if vmdplugin_ABIVERSION > 9
00263   if (can_read_angles()) {
00264     int numangles, *angles, *angletypes, numangletypes;
00265     int numdihedrals, *dihedrals, *dihedraltypes, numdihedraltypes;
00266     int numimpropers, *impropers, *impropertypes, numimpropertypes; 
00267     int numcterms, *cterms, ctermcols, ctermrows;
00268     char **angletypenames, **dihedraltypenames, **impropertypenames;
00269     double *angleforces, *dihedralforces, *improperforces, *ctermforces;
00270 
00271     // initialize to empty so that the rest of the code works well.
00272     angletypes = dihedraltypes = impropertypes = NULL;
00273     numangletypes = numdihedraltypes = numimpropertypes = 0;
00274     angletypenames = dihedraltypenames = impropertypenames = NULL;
00275     angleforces = dihedralforces = improperforces = ctermforces = NULL;
00276     
00277 #if vmdplugin_ABIVERSION >= 16
00278     if (plugin->read_angles(rv, &numangles, &angles, &angletypes, 
00279                             &numangletypes, &angletypenames, &numdihedrals,
00280                             &dihedrals,  &dihedraltypes, &numdihedraltypes, 
00281                             &dihedraltypenames, &numimpropers, &impropers,
00282                             &impropertypes, &numimpropertypes, 
00283                             &impropertypenames, &numcterms, &cterms, 
00284                             &ctermcols, &ctermrows))
00285       
00286 #else
00287     if (plugin->read_angles(rv, 
00288                             &numangles, &angles, &angleforces,
00289                             &numdihedrals, &dihedrals, &dihedralforces,
00290                             &numimpropers, &impropers, &improperforces,
00291                             &numcterms, &cterms, &ctermcols, &ctermrows, 
00292                             &ctermforces)) 
00293 #endif
00294     {
00295       msgErr << "Error reading angle and cross-term information." << sendmsg;
00296     } else {
00297       // we consider angles, dihedrals and impropers all as "angles".
00298       // it is hard to come up with a scenario where something else
00299       // as an all-or-nothing setup would happen.
00300       if ( (angletypes != NULL) || (dihedraltypes != NULL) 
00301            || (impropertypes != NULL) )
00302         m->set_dataset_flag(BaseMolecule::ANGLETYPES);
00303 
00304       // insert type names into our pool of names. this will preserve 
00305       // the indexing if no other names do already exist.
00306       if (angletypenames != NULL)
00307         for (i=0; i < numangletypes; i++)
00308           m->angleTypeNames.add_name(angletypenames[i], i);
00309 
00310       if (dihedraltypenames != NULL)
00311         for (i=0; i < numdihedraltypes; i++)
00312           m->dihedralTypeNames.add_name(dihedraltypenames[i], i);
00313 
00314       if (impropertypenames != NULL)
00315         for (i=0; i < numimpropertypes; i++)
00316           m->improperTypeNames.add_name(impropertypenames[i], i);
00317 
00318       // XXX: using a similar interface as with bonds would become
00319       //      quite complicated. not sure if it is really needed.
00320       //      for the moment we forgo it and force a simple all-or-nothing
00321       //      scheme instead. incrementally adding and removing of
00322       //      angles has to be done from (topology building) scripts.
00323       if (numangles > 0 || numdihedrals > 0 || numimpropers > 0) {
00324         m->set_dataset_flag(BaseMolecule::ANGLES);
00325         m->clear_angles();
00326         if (angletypes != NULL) {
00327           int type;
00328 
00329           for (i=0; i<numangles; i++) {
00330             type = angletypes[i];
00331             if (angletypenames != NULL)
00332               type = m->angleTypeNames.typecode(angletypenames[type]);
00333 
00334             m->add_angle(angles[3*i]-1, angles[3*i+1]-1, angles[3*i+2]-1, type);
00335           }
00336         } else {
00337           for (i=0; i<numangles; i++) {
00338             m->add_angle(angles[3*i]-1, angles[3*i+1]-1, angles[3*i+2]-1);
00339           }
00340         }
00341 
00342         m->clear_dihedrals();
00343         if (dihedraltypes != NULL) {
00344           int type;
00345 
00346           for (i=0; i<numdihedrals; i++) {
00347             type = dihedraltypes[i];
00348             if (dihedraltypenames != NULL)
00349               type = m->dihedralTypeNames.typecode(dihedraltypenames[type]);
00350 
00351             m->add_dihedral(dihedrals[4*i]-1,   dihedrals[4*i+1]-1, 
00352                             dihedrals[4*i+2]-1, dihedrals[4*i+3]-1, type);
00353           }
00354         } else {
00355           for (i=0; i<numdihedrals; i++) {
00356             m->add_dihedral(dihedrals[4*i]-1,   dihedrals[4*i+1]-1, 
00357                             dihedrals[4*i+2]-1, dihedrals[4*i+3]-1);
00358           }
00359         }
00360         
00361         m->clear_impropers();
00362         if (impropertypes != NULL) {
00363           int type;
00364 
00365           for (i=0; i<numimpropers; i++) {
00366             type = impropertypes[i];
00367             if (impropertypenames != NULL)
00368               type = m->improperTypeNames.typecode(impropertypenames[type]);
00369 
00370             m->add_improper(impropers[4*i]-1,   impropers[4*i+1]-1, 
00371                             impropers[4*i+2]-1, impropers[4*i+3]-1, type);
00372           }
00373         } else {
00374           for (i=0; i<numimpropers; i++) {
00375             m->add_improper(impropers[4*i]-1,   impropers[4*i+1]-1, 
00376                             impropers[4*i+2]-1, impropers[4*i+3]-1);
00377           }
00378         }
00379       }
00380 
00381       // cross terms have no types. they are a CHARMM-only thing.
00382       if (numcterms > 0) {
00383         m->set_dataset_flag(BaseMolecule::CTERMS);
00384         for (i=0; i<numcterms; i++)
00385           m->add_cterm(cterms[8*i]-1,   cterms[8*i+1]-1, cterms[8*i+2]-1,
00386                        cterms[8*i+3]-1, cterms[8*i+4]-1, cterms[8*i+5]-1,
00387                        cterms[8*i+6]-1, cterms[8*i+7]-1);
00388       }
00389     }
00390   }
00391 #endif
00392   return MOLFILE_SUCCESS;
00393 }
00394 
00395   
00396 int MolFilePlugin::read_optional_structure(Molecule *m, int filebonds) {
00397   if (!rv) return MOLFILE_ERROR; 
00398   if (!can_read_structure()) return MOLFILE_ERROR;
00399   if (numatoms != m->nAtoms) return MOLFILE_ERROR;
00400 
00401   molfile_atom_t *atoms = (molfile_atom_t *) calloc(1, numatoms*sizeof(molfile_atom_t));
00402 
00403   int rc, i;
00404   int optflags = MOLFILE_BADOPTIONS; /* plugin must reset this correctly */
00405   if ((rc = plugin->read_structure(rv, &optflags, atoms))) {
00406     free(atoms);
00407     return rc; // propagate error to caller
00408   }
00409   if (optflags == MOLFILE_BADOPTIONS) {
00410     free(atoms);
00411     msgErr << "MolFilePlugin: plugin didn't initialize optional data flags" << sendmsg;
00412     msgErr << "MolFilePlugin: file load aborted" << sendmsg;
00413     return MOLFILE_ERROR; /* abort load, data can't be trusted */
00414   }
00415 
00416   // set molecule dataset flags
00417   if (optflags & MOLFILE_OCCUPANCY)
00418     m->set_dataset_flag(BaseMolecule::OCCUPANCY);
00419   if (optflags & MOLFILE_BFACTOR)
00420     m->set_dataset_flag(BaseMolecule::BFACTOR);
00421   if (optflags & MOLFILE_MASS)
00422     m->set_dataset_flag(BaseMolecule::MASS);
00423   if (optflags & MOLFILE_CHARGE)
00424     m->set_dataset_flag(BaseMolecule::CHARGE);
00425   if (optflags & MOLFILE_RADIUS)
00426     m->set_dataset_flag(BaseMolecule::RADIUS);
00427   if (optflags & MOLFILE_ATOMICNUMBER)
00428     m->set_dataset_flag(BaseMolecule::ATOMICNUMBER);
00429 
00430   // Force min/max atom radii to be updated since we've loaded new data
00431   if (optflags & MOLFILE_RADIUS)
00432     m->set_radii_changed();
00433 
00434   float *charge = m->charge();
00435   float *mass = m->mass();
00436   float *radius = m->radius();
00437   float *beta = m->beta();
00438   float *occupancy = m->occupancy();
00439   for (i=0; i<numatoms; i++) {
00440     if (optflags & MOLFILE_OCCUPANCY) {
00441       occupancy[i] = atoms[i].occupancy;
00442     }
00443 
00444     if (optflags & MOLFILE_BFACTOR) {
00445       beta[i] = atoms[i].bfactor;
00446     }
00447 
00448     if (optflags & MOLFILE_MASS) {
00449       mass[i] = atoms[i].mass;
00450     }
00451 
00452     if (optflags & MOLFILE_CHARGE) {
00453       charge[i] = atoms[i].charge;
00454     }
00455 
00456     if (optflags & MOLFILE_RADIUS) {
00457       radius[i] = atoms[i].radius;
00458     }
00459 
00460     if (optflags & MOLFILE_ATOMICNUMBER) {
00461       m->atom(i)->atomicnumber = atoms[i].atomicnumber;
00462     }
00463   }
00464   free(atoms);
00465 
00466   // if no bonds are added, then we do not re-analyze the structure
00467   if (!can_read_bonds()) 
00468     return MOLFILE_SUCCESS;
00469 
00470   // When tacking on trajectory frames from PDB files with CONECT records,
00471   // we have to prevent partial CONECT record bonding information from
00472   // blowing away existing connectivity information derived from 
00473   // automatic bond search results or from a previously loaded file with
00474   // complete bond information such as a PSF.  We only accept 
00475   // complete bonding connectivity updates, no partial updates are allowed.
00476   // Also bonding information updates can be disabled by the user with the
00477   // filebonds flag.
00478   if (!(optflags & MOLFILE_BONDSSPECIAL) && filebonds) {
00479     int nbonds, *from, *to, nbondtypes, *bondtype;
00480     float *bondorder;
00481     char **bondtypename;
00482   
00483     // must explicitly set these since they may are otherwise only
00484     // initialized by the read_bonds() call in the new ABI
00485     nbondtypes = 0;
00486     bondtype = NULL;
00487     bondtypename = NULL;
00488 
00489 #if vmdplugin_ABIVERSION >= 15
00490     if (plugin->read_bonds(rv, &nbonds, &from, &to, &bondorder, &bondtype, 
00491                            &nbondtypes, &bondtypename)) 
00492       return MOLFILE_SUCCESS;
00493 #else
00494     if (plugin->read_bonds(rv, &nbonds, &from, &to, &bondorder)) 
00495       return MOLFILE_SUCCESS;
00496 #endif
00497 
00498     // insert bondtype names into our pool of names. this will preserve 
00499     // the indexing if no other names do already exist.
00500     if (bondtypename != NULL)
00501       for (i=0; i < nbondtypes; i++)
00502         m->bondTypeNames.add_name(bondtypename[i], i);
00503       
00504     if (nbonds == 0) 
00505       return MOLFILE_SUCCESS;
00506 
00507     for (i=0; i<numatoms; i++) 
00508       m->atom(i)->bonds = 0;
00509 
00510     m->set_dataset_flag(BaseMolecule::BONDS);
00511     if (bondorder != NULL)
00512       m->set_dataset_flag(BaseMolecule::BONDORDERS);
00513     if (bondtype != NULL)
00514       m->set_dataset_flag(BaseMolecule::BONDTYPES);
00515 
00516     for (i=0; i<nbonds; i++) {
00517       float bo = 1;
00518       int bt = -1;
00519 
00520       if (bondorder != NULL) 
00521         bo = bondorder[i];
00522       if (bondtype != NULL) {
00523         if (bondtypename != NULL) {
00524           bt = m->bondTypeNames.typecode(bondtypename[bondtype[i]]);
00525         } else {
00526           bt = bondtype[i];
00527         }
00528       }
00529         
00530       m->add_bond(from[i]-1, to[i]-1, bo, bt); // real bond order
00531     } 
00532   } else {
00533     // if no bonds are added, then we do not re-analyze the structure
00534     return MOLFILE_SUCCESS;
00535   }
00536 
00537   // if the plugin can read angles, dihedrals, impropers, cross-terms, 
00538   // do it here...
00539 #if vmdplugin_ABIVERSION > 9
00540   if (can_read_angles()) {
00541     int numangles, *angles, *angletypes, numangletypes;
00542     int numdihedrals, *dihedrals, *dihedraltypes, numdihedraltypes;
00543     int numimpropers, *impropers, *impropertypes, numimpropertypes; 
00544     int numcterms, *cterms, ctermcols, ctermrows;
00545     char **angletypenames, **dihedraltypenames, **impropertypenames;
00546     double *angleforces, *dihedralforces, *improperforces, *ctermforces;
00547 
00548     // initialize to empty so that the rest of the code works well.
00549     angletypes = dihedraltypes = impropertypes = NULL;
00550     numangletypes = numdihedraltypes = numimpropertypes = 0;
00551     angletypenames = dihedraltypenames = impropertypenames = NULL;
00552     angleforces = dihedralforces = improperforces = ctermforces = NULL;
00553     
00554 #if vmdplugin_ABIVERSION >= 16
00555     if (plugin->read_angles(rv, &numangles, &angles, &angletypes, 
00556                             &numangletypes, &angletypenames, &numdihedrals,
00557                             &dihedrals,  &dihedraltypes, &numdihedraltypes, 
00558                             &dihedraltypenames, &numimpropers, &impropers,
00559                             &impropertypes, &numimpropertypes, 
00560                             &impropertypenames, &numcterms, &cterms, 
00561                             &ctermcols, &ctermrows))
00562       
00563 #else
00564     if (plugin->read_angles(rv, 
00565                             &numangles, &angles, &angleforces,
00566                             &numdihedrals, &dihedrals, &dihedralforces,
00567                             &numimpropers, &impropers, &improperforces,
00568                             &numcterms, &cterms, &ctermcols, &ctermrows, 
00569                             &ctermforces)) 
00570 #endif
00571     {
00572       msgErr << "Error reading angle and cross-term information." << sendmsg;
00573     } else {
00574       // we consider angles, dihedrals and impropers all as "angles".
00575       // it is hard to come up with a scenario where something else
00576       // as an all-or-nothing setup would happen.
00577       if ( (angletypes != NULL) || (dihedraltypes != NULL) 
00578            || (impropertypes != NULL) )
00579         m->set_dataset_flag(BaseMolecule::ANGLETYPES);
00580 
00581       // insert type names into our pool of names. this will preserve 
00582       // the indexing if no other names do already exist.
00583       if (angletypenames != NULL)
00584         for (i=0; i < numangletypes; i++)
00585           m->angleTypeNames.add_name(angletypenames[i], i);
00586 
00587       if (dihedraltypenames != NULL)
00588         for (i=0; i < numdihedraltypes; i++)
00589           m->dihedralTypeNames.add_name(dihedraltypenames[i], i);
00590 
00591       if (impropertypenames != NULL)
00592         for (i=0; i < numimpropertypes; i++)
00593           m->improperTypeNames.add_name(impropertypenames[i], i);
00594 
00595       // XXX: using a similar interface as with bonds would become
00596       //      quite complicated. not sure if it is really needed.
00597       //      for the moment we force a simple all-or-nothing
00598       //      scheme and only allow incrementally adding and removing
00599       //      angles from (topology building) scripts.
00600       if (numangles > 0 || numdihedrals > 0 || numimpropers > 0) {
00601         m->set_dataset_flag(BaseMolecule::ANGLES);
00602         m->clear_angles();
00603         if (angletypes != NULL) {
00604           int type;
00605 
00606           for (i=0; i<numangles; i++) {
00607             type = angletypes[i];
00608             if (angletypenames != NULL)
00609               type = m->angleTypeNames.typecode(angletypenames[type]);
00610 
00611             m->add_angle(angles[3*i]-1, angles[3*i+1]-1, angles[3*i+2]-1, type);
00612           }
00613         } else {
00614           for (i=0; i<numangles; i++) {
00615             m->add_angle(angles[3*i]-1, angles[3*i+1]-1, angles[3*i+2]-1);
00616           }
00617         }
00618 
00619         m->clear_dihedrals();
00620         if (dihedraltypes != NULL) {
00621           int type;
00622 
00623           for (i=0; i<numdihedrals; i++) {
00624             type = dihedraltypes[i];
00625             if (dihedraltypenames != NULL)
00626               type = m->dihedralTypeNames.typecode(dihedraltypenames[type]);
00627 
00628             m->add_dihedral(dihedrals[4*i]-1,   dihedrals[4*i+1]-1, 
00629                             dihedrals[4*i+2]-1, dihedrals[4*i+3]-1, type);
00630           }
00631         } else {
00632           for (i=0; i<numdihedrals; i++) {
00633             m->add_dihedral(dihedrals[4*i]-1,   dihedrals[4*i+1]-1, 
00634                             dihedrals[4*i+2]-1, dihedrals[4*i+3]-1);
00635           }
00636         }
00637         
00638         m->clear_impropers();
00639         if (impropertypes != NULL) {
00640           int type;
00641 
00642           for (i=0; i<numimpropers; i++) {
00643             type = impropertypes[i];
00644             if (impropertypenames != NULL)
00645               type = m->improperTypeNames.typecode(impropertypenames[type]);
00646 
00647             m->add_improper(impropers[4*i]-1,   impropers[4*i+1]-1, 
00648                             impropers[4*i+2]-1, impropers[4*i+3]-1, type);
00649           }
00650         } else {
00651           for (i=0; i<numimpropers; i++) {
00652             m->add_improper(impropers[4*i]-1,   impropers[4*i+1]-1, 
00653                             impropers[4*i+2]-1, impropers[4*i+3]-1);
00654           }
00655         }
00656       }
00657 
00658       // cross terms have no types. they are a CHARMM-only thing.
00659       if (numcterms > 0) {
00660         m->set_dataset_flag(BaseMolecule::CTERMS);
00661         for (i=0; i<numcterms; i++)
00662           m->add_cterm(cterms[8*i]-1,   cterms[8*i+1]-1, cterms[8*i+2]-1,
00663                        cterms[8*i+3]-1, cterms[8*i+4]-1, cterms[8*i+5]-1,
00664                        cterms[8*i+6]-1, cterms[8*i+7]-1);
00665       }
00666     }
00667   }
00668 #endif
00669 
00670   // (re)analyze the molecular structure, since bonds/angles/etc
00671   // may have been changed
00672   m->analyze();
00673 
00674   // force all reps and selections to be recalculated
00675   m->force_recalc(DrawMolItem::COL_REGEN | DrawMolItem::SEL_REGEN);
00676 
00677   // force secondary structure to be recalculated
00678   m->invalidate_ss(); 
00679  
00680   return MOLFILE_SUCCESS;
00681 }
00682 
00683 void MolFilePlugin::set_natoms(int n) {
00684   numatoms = n;
00685 }
00686 
00687 int MolFilePlugin::init_read(const char *file) {
00688   rv = NULL;
00689   if (can_read_structure() || can_read_timesteps() || can_read_graphics() ||
00690       can_read_volumetric() || can_read_metadata() || can_read_qm()) { 
00691     rv = plugin->open_file_read(file, plugin->name, &numatoms);
00692   }
00693   if (!rv) return MOLFILE_ERROR;
00694   delete [] _filename;
00695   _filename = stringdup(file);
00696   return MOLFILE_SUCCESS;
00697 }
00698 
00699 Timestep *MolFilePlugin::next(Molecule *m) {
00700   if (!rv) return NULL;
00701   if (numatoms <= 0) return NULL;
00702   if (!(can_read_timesteps() || can_read_qm_timestep())) return NULL;
00703   molfile_timestep_t timestep;
00704   memset(&timestep, 0, sizeof(molfile_timestep_t));
00705 
00706   // allocate space for velocities only if 
00707   // 1) the plugin implements read_timestep_metadata;
00708   // 2) metadata->has_velocities is TRUE.
00709   float *velocities = NULL;
00710 
00711   // XXX this needs to be pulled out into the read init code
00712   // rather than being done once per timestep
00713 #if vmdplugin_ABIVERSION > 10
00714   molfile_timestep_metadata_t meta;
00715   if (can_read_timestep_metadata()) {
00716     memset(&meta, 0, sizeof(molfile_timestep_metadata));
00717     plugin->read_timestep_metadata(rv, &meta);
00718     if (meta.has_velocities) {
00719       velocities = new float[3*numatoms];
00720     }
00721   }
00722 #endif
00723 
00724 #if vmdplugin_ABIVERSION > 11
00725   // QM timestep metadata can be different on every single timestep
00726   // so we need to query it prior to reading the timestep so we can 
00727   // allocate the right buffer sizes etc. 
00728   molfile_qm_timestep_metadata_t qmmeta;
00729   if (can_read_qm_timestep_metadata()) {
00730     memset(&qmmeta, 0, sizeof(molfile_qm_timestep_metadata));
00731     // XXX need to add timestep parameter or other method to specify
00732     //     which frame this applies to, else keep it the way it is
00733     //     and rename the plugin function appropriately.
00734     plugin->read_qm_timestep_metadata(rv, &qmmeta);
00735   }
00736 #endif
00737 
00738   // set useful defaults for unit cell information
00739   // a non-periodic structure has cell lengths of zero
00740   // if it's periodic in less than 3 dimensions, then only the
00741   // periodic directions will be non-zero.
00742   timestep.A = timestep.B = timestep.C = 0.0f;
00743 
00744   // cells are rectangular until told otherwise
00745   timestep.alpha = timestep.beta = timestep.gamma = 90.0f;
00746 
00747   Timestep *ts = new Timestep(numatoms);
00748   timestep.coords = ts->pos; 
00749 #if vmdplugin_ABIVERSION > 10
00750   timestep.velocities = velocities;
00751 #endif
00752   ts->vel = velocities;
00753  
00754   int rc = 0;
00755 #if vmdplugin_ABIVERSION > 11
00756   molfile_qm_metadata_t *qm_metadata = NULL; // this just a dummy
00757   molfile_qm_timestep_t qm_timestep;
00758   memset(&qm_timestep, 0, sizeof(molfile_qm_timestep_t));
00759 #endif
00760 
00761   // XXX this needs to be fixed so that a file format that can 
00762   //     optionally contain either QM or non-QM data will work correctly
00763   if (can_read_qm_timestep()) {
00764 #if vmdplugin_ABIVERSION > 11
00765     qm_timestep.scfenergies = new double[qmmeta.num_scfiter];
00766     qm_timestep.wave = new molfile_qm_wavefunction_t[qmmeta.num_wavef];
00767     memset(qm_timestep.wave, 0, qmmeta.num_wavef*sizeof(molfile_qm_wavefunction_t));
00768     int i;
00769     for (i=0; (i<MOLFILE_MAXWAVEPERTS && i<qmmeta.num_wavef); i++) {
00770       qm_timestep.wave[i].wave_coeffs = 
00771         new float[qmmeta.num_orbitals_per_wavef[i]*qmmeta.wavef_size];
00772       if (qmmeta.has_orben_per_wavef[i]) {
00773         qm_timestep.wave[i].orbital_energies =
00774           new float[qmmeta.num_orbitals_per_wavef[i]];
00775       }
00776       if (qmmeta.has_occup_per_wavef[i]) {
00777         qm_timestep.wave[i].occupancies = 
00778           new float[qmmeta.num_orbitals_per_wavef[i]];
00779       }
00780     }
00781     if (qmmeta.has_gradient) {
00782       qm_timestep.gradient = new float[3*numatoms];
00783     }
00784     if (qmmeta.num_charge_sets) {
00785       qm_timestep.charges = new double[numatoms*qmmeta.num_charge_sets];
00786       qm_timestep.charge_types = new int[qmmeta.num_charge_sets];
00787     }
00788     rc = plugin->read_timestep(rv, numatoms, &timestep, qm_metadata, &qm_timestep);
00789 #endif
00790   } else {
00791     rc = plugin->read_next_timestep(rv, numatoms, &timestep);
00792   }
00793 
00794   if (rc) {
00795 #if vmdplugin_ABIVERSION > 11
00796     if (can_read_qm_timestep()) {
00797       delete [] qm_timestep.scfenergies;
00798       if (qm_timestep.gradient) delete [] qm_timestep.gradient;
00799       if (qm_timestep.charges)  delete [] qm_timestep.charges;
00800       if (qm_timestep.charge_types) delete [] qm_timestep.charge_types;
00801       int i;
00802       for (i=0; i<qmmeta.num_wavef; i++) {
00803         delete [] qm_timestep.wave[i].wave_coeffs;
00804         delete [] qm_timestep.wave[i].orbital_energies;
00805       }
00806       delete [] qm_timestep.wave;
00807     }
00808 #endif
00809     delete ts;
00810     ts = NULL; 
00811   } else {
00812     ts->a_length = timestep.A;
00813     ts->b_length = timestep.B;
00814     ts->c_length = timestep.C;
00815     ts->alpha = timestep.alpha;
00816     ts->beta = timestep.beta;
00817     ts->gamma = timestep.gamma;
00818 #if vmdplugin_ABIVERSION > 10
00819     ts->physical_time = timestep.physical_time;
00820 #endif
00821 #if vmdplugin_ABIVERSION > 11
00822     if (can_read_qm_timestep()) {
00823       int i;
00824       int *chargetypes = new int[qmmeta.num_charge_sets];
00825       for (i=0; i<qmmeta.num_charge_sets; i++) {
00826         switch (qm_timestep.charge_types[i]) {
00827         case  MOLFILE_QMCHARGE_MULLIKEN:
00828           chargetypes[i] = QMCHARGE_MULLIKEN;
00829           break;
00830         case MOLFILE_QMCHARGE_LOWDIN:
00831           chargetypes[i] = QMCHARGE_LOWDIN;
00832           break;
00833         case MOLFILE_QMCHARGE_ESP:
00834           chargetypes[i] = QMCHARGE_ESP;
00835           break;
00836         case MOLFILE_QMCHARGE_NPA:
00837           chargetypes[i] = QMCHARGE_NPA;
00838           break;
00839         default:
00840           chargetypes[i] = QMCHARGE_UNKNOWN;
00841         }
00842       }
00843 
00844       ts->qm_timestep = new QMTimestep(numatoms);
00845       ts->qm_timestep->set_charges(qm_timestep.charges,
00846                                    chargetypes,
00847                                    numatoms, qmmeta.num_charge_sets);
00848       delete [] chargetypes;
00849 
00850       ts->qm_timestep->set_scfenergies(qm_timestep.scfenergies,
00851                                        qmmeta.num_scfiter);
00852 
00853 
00854       // signa_ts is the list of numsigts signatures for the wavefunctions
00855       // already processed for this timestep. 
00856       int num_signa_ts = 0;
00857       wavef_signa_t *signa_ts = NULL;
00858       for (i=0; i<qmmeta.num_wavef; i++) {
00859         // We need to translate between the macros used in the plugins
00860         // and the one ones in VMD, here so that they can be independent
00861         // and we don't have to include molfile_plugin.h anywhere else
00862         // in VMD.
00863         int wavef_type;
00864         switch (qm_timestep.wave[i].type) {
00865         case MOLFILE_WAVE_CANON:
00866           wavef_type = WAVE_CANON;
00867           break;
00868         case MOLFILE_WAVE_CINATUR:
00869           wavef_type = WAVE_CINATUR;
00870           break;
00871         case MOLFILE_WAVE_GEMINAL:
00872           wavef_type = WAVE_GEMINAL;
00873           break;
00874         case MOLFILE_WAVE_BOYS:
00875           wavef_type = WAVE_BOYS;
00876           break;
00877         case MOLFILE_WAVE_RUEDEN:
00878           wavef_type = WAVE_RUEDEN;
00879           break;
00880         case MOLFILE_WAVE_PIPEK:
00881           wavef_type = WAVE_PIPEK;
00882           break;
00883         case MOLFILE_WAVE_MCSCFOPT:
00884           wavef_type = WAVE_MCSCFOPT;
00885           break;
00886         case MOLFILE_WAVE_MCSCFNAT:
00887           wavef_type = WAVE_MCSCFNAT;
00888           break;
00889         default:
00890           wavef_type = WAVE_UNKNOWN;
00891         }
00892 
00893         // Add new wavefunction to QM timestep
00894         ts->qm_timestep->add_wavefunction(qm_data,
00895                            qmmeta.wavef_size,
00896                            qmmeta.num_orbitals_per_wavef[i],
00897                            qm_timestep.wave[i].wave_coeffs,
00898                            qm_timestep.wave[i].orbital_energies,
00899                            qm_timestep.wave[i].occupancies,
00900                            qm_timestep.wave[i].orbital_ids,
00901                            qm_timestep.wave[i].energy,
00902                            wavef_type,
00903                            qm_timestep.wave[i].spin,
00904                            qm_timestep.wave[i].excitation,
00905                            qm_timestep.wave[i].multiplicity,
00906                            qm_timestep.wave[i].info,
00907                            signa_ts, num_signa_ts);
00908       }
00909       free(signa_ts);
00910 
00911       ts->qm_timestep->set_gradients(qm_timestep.gradient, numatoms);
00912 
00913       delete [] qm_timestep.scfenergies;
00914       if (qm_timestep.gradient)     delete [] qm_timestep.gradient;
00915       if (qm_timestep.charges)      delete [] qm_timestep.charges;
00916       if (qm_timestep.charge_types) delete [] qm_timestep.charge_types;
00917 
00918       for (i=0; i<qmmeta.num_wavef; i++) {
00919         delete [] qm_timestep.wave[i].wave_coeffs;
00920         delete [] qm_timestep.wave[i].orbital_energies;
00921         delete [] qm_timestep.wave[i].occupancies;
00922       }
00923       delete [] qm_timestep.wave;
00924 #if 0
00925       // If we have at least two timesteps then sort the orbitals
00926       // of the current timestep according to the ones from the
00927       // previous timestep.
00928       // Note that the frame counter m->numframes() is updated
00929       // after this function call. 
00930       if (m->numframes()>0) {
00931         // Get the previous Timestep
00932         Timestep *prevts = m->get_frame(m->numframes()-1);
00933 
00934         msgInfo << "sort frame " << m->numframes() << sendmsg;
00935 
00936         // Sort the orbitals by comparing them to the ones from
00937         // the previous timestep.
00938         ts->qm_timestep->sort_orbitals(prevts->qm_timestep);
00939       } else {
00940         msgInfo << "ignore frame " << m->numframes() << sendmsg;
00941       }
00942 #endif 
00943     }
00944 #endif
00945   }
00946   return ts;
00947 }
00948 
00949 int MolFilePlugin::skip(Molecule *m) {
00950   if (!rv) return MOLFILE_ERROR;
00951   if (!can_read_timesteps()) return MOLFILE_ERROR;
00952   return plugin->read_next_timestep(rv, numatoms, 0);
00953 }
00954 
00955 void MolFilePlugin::close() {
00956   if (rv && (can_read_structure() || can_read_timesteps() || 
00957              can_read_graphics() || can_read_volumetric() ||
00958              can_read_metadata() || can_read_bonds())) { 
00959     plugin->close_file_read(rv);
00960     rv = NULL;
00961   }
00962   if (wv && (can_write_structure() || can_write_timesteps() ||
00963              can_write_bonds())) { 
00964     plugin->close_file_write(wv);
00965     wv = NULL;
00966   }
00967 }
00968 
00969 int MolFilePlugin::init_write(const char *file, int natoms) {
00970   wv = NULL;
00971   if (can_write_structure() || can_write_timesteps() 
00972 #if vmdplugin_ABIVERSION > 9
00973           || can_write_volumetric()
00974 #endif
00975           ) { 
00976     wv = plugin->open_file_write(file, plugin->name, natoms);
00977   } 
00978   if (!wv) return MOLFILE_ERROR;
00979   delete [] _filename;
00980   _filename = stringdup(file);
00981 
00982   // Cache the number of atoms to be written.  It's not strictly necessary,
00983   // but it lets us allocate only the necessary space in write_structure
00984   // and write_timestep.
00985   numatoms = natoms;
00986 
00987   return MOLFILE_SUCCESS;
00988 }
00989 
00990 
00991 int MolFilePlugin::write_structure(Molecule *m, const int *on) {
00992   if (!wv) return MOLFILE_ERROR;
00993   if (!can_write_structure()) return MOLFILE_ERROR;
00994   if (!m->has_structure()) {
00995     msgErr << "Molecule's structure has not been initialized." << sendmsg;
00996     return MOLFILE_ERROR;
00997   }
00998   
00999   int i, j, k;
01000   molfile_atom_t *atoms = (molfile_atom_t *) calloc(1, numatoms*sizeof(molfile_atom_t));
01001   int *atomindexmap = (int *) calloc(1, m->nAtoms*sizeof(int));
01002 
01003   // initialize the atom index map to an invalid atom index value, so that
01004   // we can use this to eliminate bonds to atoms that aren't selected.
01005   for (i=0; i<m->nAtoms; i++) 
01006     atomindexmap[i] = -1;
01007 
01008   const float *charge = m->charge();
01009   const float *mass = m->mass();
01010   const float *radius = m->radius();
01011   const float *beta = m->beta();
01012   const float *occupancy = m->occupancy();
01013 
01014   int mangleatomnames = 1;
01015   if (getenv("VMDNOMANGLEATOMNAMES")) {
01016     mangleatomnames = 0;
01017   }
01018 
01019   // build the array of selected atoms to be written out
01020   for (i=0, j=0; i<m->nAtoms; i++) {
01021     // skip atoms that aren't 'on', if we've been given an 'on' array
01022     if (on && !on[i]) 
01023       continue;
01024 
01025     // Check that the number of atoms specified in init_write is no smaller
01026     // than the number of atoms in the selection; otherwise we would 
01027     // corrupt memory.
01028     if (j >= numatoms) {
01029       msgErr << 
01030         "MolFilePlugin: Internal error, selection size exceeds numatoms ("
01031         << numatoms << ")" << sendmsg;
01032       free(atoms);
01033       free(atomindexmap);
01034       return MOLFILE_ERROR;
01035     }
01036 
01037     const MolAtom *atom = m->atom(i);
01038     molfile_atom_t &atm = atoms[j];
01039 
01040     if (mangleatomnames) {
01041       // Try to restore the spacing on the name since VMD destroys it when it
01042       // reads it in.
01043       // XXX this is PDB-centric thinking, need to reconsider this
01044       char name[6], *nameptr;
01045       name[0] = ' ';
01046       strncpy(name+1, (m->atomNames).name(atom->nameindex), 4);
01047       name[5] = '\0';
01048       // the name must be left-justified
01049       if(strlen(name) == 5) {
01050         nameptr = name + 1;
01051       } else {
01052         nameptr = name;
01053         int p;
01054         while((p = strlen(name)) < 4) {
01055           name[p] = ' ';
01056           name[p+1] = '\0';
01057         }
01058       }
01059       strcpy(atm.name, nameptr);
01060     } else {
01061       strncpy(atm.name, m->atomNames.name(atom->nameindex), sizeof(atm.name));
01062     }
01063 
01064     strcpy(atm.type, m->atomTypes.name(atom->typeindex));
01065     strcpy(atm.resname, m->resNames.name(atom->resnameindex));
01066     atm.resid = atom->resid;
01067     strcpy(atm.chain, m->chainNames.name(atom->chainindex));
01068     strcpy(atm.segid, m->segNames.name(atom->segnameindex));
01069     strcpy(atm.insertion, atom->insertionstr);
01070     strcpy(atm.altloc, m->altlocNames.name(atom->altlocindex));
01071     atm.atomicnumber = atom->atomicnumber;
01072     atm.occupancy = occupancy[i];
01073     atm.bfactor = beta[i];
01074     atm.mass = mass[i]; 
01075     atm.charge = charge[i]; 
01076     atm.radius = radius[i];
01077 
01078     atomindexmap[i] = j; // build index map for bond/angle/dihedral/cterms
01079 
01080     j++;
01081   }
01082 
01083   // check that the selection size matches numatoms
01084   if (j != numatoms) {
01085     msgErr 
01086       << "MolFilePlugin: Internal error, selection size (" << j 
01087       << ") doesn't match numatoms (" << numatoms << ")" << sendmsg;
01088     free (atoms);
01089     return MOLFILE_ERROR;
01090   }
01091 
01092   // set optional data fields we're providing
01093   int optflags = MOLFILE_NOOPTIONS; // initialize optflags
01094 
01095   if (m->test_dataset_flag(BaseMolecule::INSERTION))
01096     optflags |= MOLFILE_INSERTION;
01097 
01098   if (m->test_dataset_flag(BaseMolecule::OCCUPANCY))
01099     optflags |= MOLFILE_OCCUPANCY;
01100 
01101   if (m->test_dataset_flag(BaseMolecule::BFACTOR))
01102     optflags |= MOLFILE_BFACTOR;
01103 
01104   if (m->test_dataset_flag(BaseMolecule::MASS))
01105     optflags |= MOLFILE_MASS;
01106 
01107   if (m->test_dataset_flag(BaseMolecule::CHARGE))
01108     optflags |= MOLFILE_CHARGE;
01109 
01110   if (m->test_dataset_flag(BaseMolecule::RADIUS))
01111     optflags |= MOLFILE_RADIUS;
01112   
01113   if (m->test_dataset_flag(BaseMolecule::ALTLOC))
01114     optflags |= MOLFILE_ALTLOC;
01115 
01116   if (m->test_dataset_flag(BaseMolecule::ATOMICNUMBER))
01117     optflags |= MOLFILE_ATOMICNUMBER;
01118 
01119   // Build and save a bond list if this plugin has a write_bonds() callback.
01120   // Bonds must be specified to the plugin before write_structure() is called.
01121   // Only store bond information if it was either set by the user or 
01122   // by loading from other files.  We don't save auto-generated bond info 
01123   // by default anymore.  We consider auto-generated bonds worth saving
01124   // only if the user has customized other bond properties.
01125   if (can_write_bonds() && 
01126       (m->test_dataset_flag(BaseMolecule::BONDS) ||
01127        m->test_dataset_flag(BaseMolecule::BONDORDERS) ||
01128        m->test_dataset_flag(BaseMolecule::BONDTYPES))) {
01129     ResizeArray<int> bondfrom, bondto; 
01130     ResizeArray<float> bondorder;
01131     ResizeArray<int> bondtype;
01132     ResizeArray<char *>bondtypename;
01133     
01134     float *bondorderptr=NULL;
01135     int *bondtypeptr=NULL;
01136     char **bondtypenameptr=NULL;
01137     int numbondtypes=0;
01138     
01139     for (i=0; i<m->nAtoms; i++) {
01140       const MolAtom *atom = m->atom(i);
01141       int bfmap = atomindexmap[i] + 1; // 1-based mapped atom index
01142 
01143       for (k=0; k<atom->bonds; k++) {
01144         int bto = atom->bondTo[k];
01145         int btmap = atomindexmap[bto] + 1; // 1-based mapped atom index
01146  
01147         // add 1-based bonds to 'on' atoms to the bond list
01148         if (bfmap > 0 && btmap > bfmap) {
01149           bondfrom.append(bfmap);
01150           bondto.append(btmap);
01151           bondorder.append(m->getbondorder(i, k)); 
01152           bondtype.append(m->getbondtype(i, k));
01153         }
01154       }
01155     } 
01156 
01157     // only store bond orders if they were set by the user or read in 
01158     // from files 
01159     if (m->test_dataset_flag(BaseMolecule::BONDORDERS))
01160       bondorderptr=&bondorder[0];
01161     else 
01162       bondorderptr=NULL; // no bond orders provided
01163 
01164     numbondtypes = m->bondTypeNames.num();
01165     for (i=0; i < numbondtypes; i++) {
01166       bondtypename.append((char *)m->bondTypeNames.name(i));
01167     }
01168     if (numbondtypes > 0)
01169       bondtypenameptr = &bondtypename[0];
01170     else 
01171       bondtypenameptr = NULL;
01172     
01173     // only store bond types if they were set by the user or read in 
01174     // from files 
01175     if (m->test_dataset_flag(BaseMolecule::BONDTYPES))
01176       bondtypeptr= &bondtype[0];
01177     else 
01178       bondtypeptr=NULL; // no bond types provided
01179 
01180 #if vmdplugin_ABIVERSION >= 15
01181     if (plugin->write_bonds(wv, bondfrom.num(), &bondfrom[0], &bondto[0], 
01182                             bondorderptr, bondtypeptr, 
01183                             numbondtypes, bondtypenameptr)) {
01184 #else
01185     if (plugin->write_bonds(wv, bondfrom.num(), &bondfrom[0], &bondto[0], 
01186                             bondorderptr)) {
01187 #endif
01188       free(atoms);
01189       free(atomindexmap);
01190       return MOLFILE_ERROR;
01191     }
01192   }
01193 
01194 #if vmdplugin_ABIVERSION > 9
01195   // Only write angle info if all atoms are selected.
01196   // It's not clear whether there's a point in trying to preserve this
01197   // kind of information when writing out a sub-structure from an 
01198   // atom selection.
01199   if (can_write_angles() && m->test_dataset_flag(BaseMolecule::ANGLES)) {
01200     ResizeArray<int> angles;
01201     ResizeArray<int> angleTypes;
01202     ResizeArray<const char *>angleTypeNames;
01203     ResizeArray<int> dihedrals;
01204     ResizeArray<int> dihedralTypes;
01205     ResizeArray<const char *>dihedralTypeNames;
01206     ResizeArray<int> impropers;
01207     ResizeArray<int> improperTypes;
01208     ResizeArray<const char *>improperTypeNames;
01209     ResizeArray<int> cterms;
01210 
01211     int numangles = m->num_angles();
01212     int numdihedrals = m->num_dihedrals();
01213     int numimpropers = m->num_impropers();
01214 
01215     // generate packed arrays with 1-based indexing
01216     for (i=0; i<numangles; i++) {
01217       int idx0 = atomindexmap[m->angles[i*3    ]];
01218       int idx1 = atomindexmap[m->angles[i*3 + 1]];
01219       int idx2 = atomindexmap[m->angles[i*3 + 2]];
01220       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0)) {
01221         angles.append(idx0+1); // 1-based atom index map
01222         angles.append(idx1+1); // 1-based atom index map
01223         angles.append(idx2+1); // 1-based atom index map
01224 #if vmdplugin_ABIVERSION >= 16
01225         if (m->test_dataset_flag(BaseMolecule::ANGLETYPES)) {
01226           angleTypes.append(m->get_angletype(i));
01227         }
01228 #endif
01229       } 
01230     } 
01231     for (i=0; i<numdihedrals; i++) {
01232       int idx0 = atomindexmap[m->dihedrals[i*4    ]];
01233       int idx1 = atomindexmap[m->dihedrals[i*4 + 1]];
01234       int idx2 = atomindexmap[m->dihedrals[i*4 + 2]];
01235       int idx3 = atomindexmap[m->dihedrals[i*4 + 3]];
01236       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0) && (idx3 >= 0)) {
01237         dihedrals.append(idx0+1); // 1-based atom index map
01238         dihedrals.append(idx1+1); // 1-based atom index map
01239         dihedrals.append(idx2+1); // 1-based atom index map
01240         dihedrals.append(idx3+1); // 1-based atom index map
01241 #if vmdplugin_ABIVERSION >= 16
01242         if (m->test_dataset_flag(BaseMolecule::ANGLETYPES)) {
01243           dihedralTypes.append(m->get_dihedraltype(i));
01244         }
01245 #endif
01246       } 
01247     } 
01248     for (i=0; i<numimpropers; i++) {
01249       int idx0 = atomindexmap[m->impropers[i*4    ]];
01250       int idx1 = atomindexmap[m->impropers[i*4 + 1]];
01251       int idx2 = atomindexmap[m->impropers[i*4 + 2]];
01252       int idx3 = atomindexmap[m->impropers[i*4 + 3]];
01253       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0) && (idx3 >= 0)) {
01254         impropers.append(idx0+1); // 1-based atom index map
01255         impropers.append(idx1+1); // 1-based atom index map
01256         impropers.append(idx2+1); // 1-based atom index map
01257         impropers.append(idx3+1); // 1-based atom index map
01258 #if vmdplugin_ABIVERSION >= 16
01259         if (m->test_dataset_flag(BaseMolecule::ANGLETYPES)) {
01260           improperTypes.append(m->get_impropertype(i));
01261         }
01262 #endif
01263       } 
01264     } 
01265 
01266     int ctermcnt=0;
01267     int *ctermlist=NULL;
01268     if (m->test_dataset_flag(BaseMolecule::CTERMS)) {
01269       int numcterms = m->num_cterms();
01270       for (i=0; i<numcterms; i++) {
01271         int goodcount=0;
01272         for (j=0; j<8; j++) {
01273           if (atomindexmap[m->cterms[i*8 + j]] >= 0)
01274             goodcount++; 
01275         }
01276         if (goodcount == 8) {
01277           ctermcnt++;
01278           for (j=0; j<8; j++) {
01279             // 1-based atom index map
01280             cterms.append(atomindexmap[m->cterms[i*8 + j]]+1);
01281           }
01282         }
01283       }
01284       if (ctermcnt > 0)
01285         ctermlist = &cterms[0];
01286     }
01287 
01288 #if vmdplugin_ABIVERSION >= 16
01289     // copy all names.
01290     if (m->test_dataset_flag(BaseMolecule::ANGLETYPES)) {
01291       for (i=0; i < m->angleTypeNames.num(); i++)
01292         angleTypeNames.append(m->angleTypeNames.name(i));
01293       for (i=0; i < m->dihedralTypeNames.num(); i++)
01294         dihedralTypeNames.append(m->dihedralTypeNames.name(i));
01295       for (i=0; i < m->improperTypeNames.num(); i++)
01296         improperTypeNames.append(m->improperTypeNames.name(i));
01297     }
01298 #endif
01299     
01300     int anglescnt         = angles.num()/3;
01301     int *anglelist        = (anglescnt    > 0) ? &angles[0] : NULL;
01302 #if vmdplugin_ABIVERSION >= 16
01303     int *angletypelist    = (angleTypes.num() > 0) ? &angleTypes[0] : NULL;
01304     int angletypecnt      = angleTypeNames.num();
01305     const char **anglenmlist = (angletypecnt>0) ? &angleTypeNames[0] : NULL;
01306 #endif
01307 
01308     int dihedralscnt      = dihedrals.num()/4;
01309     int *dihedrallist     = (dihedralscnt > 0) ? &dihedrals[0] : NULL;
01310 #if vmdplugin_ABIVERSION >= 16
01311     int *dihedraltypelist = (dihedralTypes.num() > 0) ? &dihedralTypes[0] : NULL;
01312     int dihedraltypecnt   = dihedralTypeNames.num();
01313     const char **dihedralnmlist = (dihedraltypecnt>0) ? &dihedralTypeNames[0] : NULL;
01314 #endif
01315 
01316     int improperscnt      = impropers.num()/4;
01317     int *improperlist     = (improperscnt > 0) ? &impropers[0] : NULL;
01318 #if vmdplugin_ABIVERSION >= 16
01319     int *impropertypelist = (improperTypes.num() > 0) ? &improperTypes[0] : NULL;
01320     int impropertypecnt   = improperTypeNames.num();
01321     const char **impropernmlist = (impropertypecnt>0) ? &improperTypeNames[0] : NULL;
01322     if (plugin->write_angles(wv, anglescnt, anglelist, angletypelist, angletypecnt, 
01323                              anglenmlist, dihedralscnt, dihedrallist, dihedraltypelist,
01324                              dihedraltypecnt, dihedralnmlist, improperscnt, 
01325                              improperlist, impropertypelist, impropertypecnt, 
01326                              impropernmlist, ctermcnt, ctermlist, 0, 0)) {
01327       free(atoms);
01328       free(atomindexmap);
01329       return MOLFILE_ERROR;
01330     }
01331 #else
01332     if (plugin->write_angles(wv, anglescnt, anglelist, NULL,
01333                              dihedralscnt, dihedrallist, NULL,
01334                              improperscnt, improperlist, NULL,
01335                              ctermcnt, ctermlist, 0, 0, NULL)) {
01336       free(atoms);
01337       free(atomindexmap);
01338       return MOLFILE_ERROR;
01339     }
01340 #endif
01341   }
01342 #endif
01343 
01344   // write the structure
01345   if (plugin->write_structure(wv, optflags, atoms)) {
01346     free(atoms);
01347     free(atomindexmap);
01348     return MOLFILE_ERROR;
01349   }
01350 
01351   free(atoms);
01352   free(atomindexmap);
01353 
01354   return MOLFILE_SUCCESS;
01355 }
01356  
01357 int MolFilePlugin::write_timestep(const Timestep *ts, const int *on) {
01358   // it isn't an error if this file format doesn't write timesteps
01359   if (!can_write_timesteps()) 
01360     return MOLFILE_SUCCESS; 
01361 
01362   molfile_timestep_t mol_ts;
01363   memset(&mol_ts, 0, sizeof(molfile_timestep_t));
01364   mol_ts.A = ts->a_length;
01365   mol_ts.B = ts->b_length;
01366   mol_ts.C = ts->c_length;
01367   mol_ts.alpha = ts->alpha;
01368   mol_ts.beta = ts->beta;
01369   mol_ts.gamma = ts->gamma;
01370 #if vmdplugin_ABIVERSION > 10
01371   mol_ts.physical_time = ts->physical_time;
01372 #endif
01373   if (!on) {
01374     mol_ts.coords = ts->pos;
01375     mol_ts.velocities = ts->vel;
01376     return plugin->write_timestep(wv, &mol_ts);
01377   }
01378   float *coords = new float[3*numatoms];
01379   float *vel = NULL;
01380   if (ts->vel) vel = new float[3*numatoms];
01381   int j=0;
01382   for (int i=0; i<ts->num; i++) {
01383     if (on[i]) {
01384       if (on && !on[i]) continue;
01385       // check that the selection doesn't contain too many atoms
01386       if (j >= 3*numatoms) {
01387         msgErr << "MolFilePlugin::write_timestep: Internal error" << sendmsg;
01388         msgErr << "Selection size exceeds numatoms (" << numatoms << ")" 
01389                << sendmsg;
01390         delete [] coords;
01391         delete vel;
01392         return MOLFILE_ERROR;
01393       }
01394       coords[j  ] = ts->pos[3*i];
01395       coords[j+1] = ts->pos[3*i+1];
01396       coords[j+2] = ts->pos[3*i+2];
01397       if (ts->vel) {
01398         vel[j  ] = ts->vel[3*i  ];
01399         vel[j+1] = ts->vel[3*i+1];
01400         vel[j+2] = ts->vel[3*i+2];
01401       }
01402       j += 3;
01403     }
01404   }
01405   // check that the selection size matches numatoms
01406   if (j != 3*numatoms) {
01407     msgErr << "MolFilePlugin::write_timestep: Internal error" << sendmsg;
01408     msgErr << "selection size (" << j << ") doesn't match numatoms (" 
01409            << numatoms << ")" << sendmsg;
01410     delete [] coords;
01411     return MOLFILE_ERROR;
01412   }
01413   mol_ts.coords = coords;
01414   mol_ts.velocities = vel;
01415   int rc = plugin->write_timestep(wv, &mol_ts);
01416   delete [] coords;
01417   delete vel;
01418   return rc;
01419 }
01420  
01421 int MolFilePlugin::read_rawgraphics(Molecule *m, Scene *sc) {
01422   if (!rv || !can_read_graphics()) return MOLFILE_ERROR;
01423   const molfile_graphics_t *graphics = NULL;
01424   int nelem = -1;
01425   if (plugin->read_rawgraphics(rv, &nelem, &graphics)) return MOLFILE_ERROR;
01426   msgInfo << "Reading " << nelem << " graphics elements..." << sendmsg;
01427   MoleculeGraphics *mg = m->moleculeGraphics();
01428   for (int i=0; i<nelem; i++) {
01429     const float *data = graphics[i].data;
01430     switch (graphics[i].type) {
01431       case MOLFILE_POINT: 
01432         mg->add_point(data); 
01433         break;
01434       case MOLFILE_TRIANGLE:
01435         mg->add_triangle(data, data+3, data+6);
01436         break;
01437       case MOLFILE_TRINORM:
01438         {
01439           const float *ndata;
01440           // next element must be the norms
01441           if (i+1 >= nelem || graphics[i+1].type != MOLFILE_NORMS) {
01442             msgErr << "Invalid rawgraphics: NORMS must follow TRINORM."
01443               << sendmsg;
01444             return MOLFILE_ERROR;
01445           }
01446           ++i;
01447           ndata = graphics[i].data;
01448           mg->add_trinorm(data, data+3, data+6, ndata, ndata+3, ndata+6);
01449         }
01450         break;
01451       case MOLFILE_TRICOLOR: 
01452         {
01453           const float *ndata, *cdata;
01454           // next element must be the norms
01455           if (i+1 >= nelem || graphics[i+1].type != MOLFILE_NORMS) {
01456             msgErr << "Invalid rawgraphics: NORMS must follow TRINORM."
01457               << sendmsg;
01458             return MOLFILE_ERROR;
01459           }
01460           ++i;
01461           ndata = graphics[i].data;
01462           // next element must be the vertex colors
01463           if (i+1 >= nelem || graphics[i+1].type != MOLFILE_COLOR) {
01464             msgErr << "Invalid rawgraphics: NORMS and COLOR must fullow TRICOLOR."
01465               << sendmsg;
01466             return MOLFILE_ERROR;
01467           }
01468           ++i;
01469           cdata = graphics[i].data;
01470           mg->add_tricolor(data, data+3, data+6, ndata, ndata+3, ndata+6,
01471               sc->nearest_index(cdata[0], cdata[1], cdata[2]), 
01472               sc->nearest_index(cdata[3], cdata[4], cdata[5]), 
01473               sc->nearest_index(cdata[6], cdata[7], cdata[8]));
01474         }
01475         break;
01476       case MOLFILE_LINE:
01477         mg->add_line(data, data+3, graphics[i].style, (int)graphics[i].size);
01478         break;
01479       case MOLFILE_CYLINDER:
01480         mg->add_cylinder(data, data+3, graphics[i].size, graphics[i].style, 0);
01481         break;
01482       case MOLFILE_CAPCYL:
01483         mg->add_cylinder(data, data+3, graphics[i].size, graphics[i].style, 1);
01484         break;
01485       case MOLFILE_CONE:
01486         mg->add_cone(data, data+3, graphics[i].size, data[6], graphics[i].style);
01487         break;
01488       case MOLFILE_SPHERE:
01489         mg->add_sphere(data, graphics[i].size, graphics[i].style);
01490         break;
01491       case MOLFILE_TEXT:
01492         {
01493           char text[24];
01494           strncpy(text, (char *)data+3, 24);
01495           text[23] = '\0';
01496           mg->add_text(data, text, graphics[i].size, 1.0f);
01497         }
01498         break;
01499       case MOLFILE_COLOR:
01500         mg->use_color(sc->nearest_index(data[0], data[1], data[2]));
01501         break;
01502       case MOLFILE_NORMS:
01503         msgErr << "Invalid rawgraphics: NORMS must follow TRINORM." << sendmsg;
01504         return MOLFILE_ERROR;
01505         break;
01506       default:
01507         msgErr << "Invalid rawgraphics: unknown type " << graphics[i].type
01508                << sendmsg;
01509     }
01510   }
01511 
01512   return MOLFILE_SUCCESS;
01513 }
01514 
01515 
01516 int MolFilePlugin::read_volumetric(Molecule *m, int nsets, 
01517     const int *setids) {
01518 
01519   // Fetch metadata from file
01520   molfile_volumetric_t *metadata;
01521   int setsinfile = 0;
01522   plugin->read_volumetric_metadata(rv, &setsinfile, &metadata);
01523 
01524   // Get datasets specified in setids
01525   int n;
01526   int *sets;
01527   if (nsets < 0) {
01528     n = setsinfile;
01529     sets = new int[n];
01530     for (int i=0; i<n; i++) sets[i] = i;
01531   } else {
01532     n = nsets;
01533     sets = new int [n];
01534     for (int i=0; i<n; i++) sets[i] = setids[i];
01535   }
01536 
01537   for (int i=0; i< n; i++) {
01538     if (sets[i] < 0 || sets[i] >= setsinfile) {
01539       msgErr << "Bogus setid passed to read_volumetric: " << sets[i]
01540              << sendmsg;
01541       continue;
01542     }  
01543     const molfile_volumetric_t *v = metadata+sets[i];
01544     float *datablock = NULL, *colorblock = NULL;
01545     size_t size = v->xsize * v->ysize * v->zsize;
01546     datablock = new float[size];
01547     if (v->has_color) 
01548       colorblock = new float[3*size];
01549     if (plugin->read_volumetric_data(rv, sets[i], datablock, colorblock)) {
01550       msgErr << "Error reading volumetric data set " << sets[i]+1 << sendmsg;
01551       delete [] datablock;
01552       delete [] colorblock;
01553       continue;
01554     }
01555     char *dataname = stringdup(v->dataname);
01556     if (_filename) {
01557       // prepend the filename to the dataname; otherwise it's hard to tell
01558       // multiple data sets apart in the GUI.  This should be done here,
01559       // within VMD, rather than within each plugin because otherwise 
01560       // different plugins will end up exhibiting different behavior with
01561       // regard to naming their datasets.
01562       //
01563       // XXX The breakup_filename command uses forward slashes only and
01564       // is therefore Unix-specific.  Also, to avoid super-long dataset
01565       // names I'm going to use just the 'basename' part of the file.
01566       // It's easier just to code a correct version of what I want here.
01567       char sep = 
01568 #ifdef WIN32
01569         '\\'
01570 #else
01571         '/'
01572 #endif
01573         ;
01574       const char *basename = strrchr(_filename, sep);
01575       if (!basename) {
01576         basename = _filename;
01577       } else {
01578         basename++; // skip the separator
01579       }
01580       char *tmp = new char[strlen(dataname)+5+strlen(basename)];
01581       sprintf(tmp, "%s : %s", basename, dataname);
01582       delete [] dataname;
01583       dataname = tmp;
01584     }
01585     m->add_volume_data(dataname, v->origin,
01586          v->xaxis, v->yaxis, v->zaxis, v->xsize, v->ysize, v->zsize,
01587          datablock);
01588     delete [] dataname;
01589     delete [] colorblock;
01590   }
01591   delete [] sets;
01592 
01593   return MOLFILE_SUCCESS;
01594 }
01595 
01596 
01597 int MolFilePlugin::read_metadata(Molecule *m) {
01598   // Fetch metadata from file
01599   molfile_metadata_t *metadata;
01600 
01601   plugin->read_molecule_metadata(rv, &metadata);
01602 
01603   m->record_database(metadata->database, metadata->accession);
01604   if (metadata->remarks != NULL) 
01605     m->record_remarks(metadata->remarks);
01606   else 
01607     m->record_remarks("");
01608 
01609   return MOLFILE_SUCCESS;
01610 }
01611 
01612 
01613 #if vmdplugin_ABIVERSION > 9
01614 int MolFilePlugin::read_qm_data(Molecule *mol) {
01615   // Fetch metadata from file.
01616   // It provides us with a bunch of sizes for the arrays
01617   // that we have to allocate and provide to read_qm_rundata().
01618   // Note that this probably should be done 
01619   molfile_qm_metadata_t metadata;
01620 
01621   // check for failures while parsing metadata and bail out if
01622   // an error occurs.
01623   if (plugin->read_qm_metadata(rv, &metadata) != MOLFILE_SUCCESS)
01624     return MOLFILE_ERROR;
01625 
01626 #if vmdplugin_ABIVERSION > 11
01627   // If the plugin didn't provide the number of atoms
01628   // (e.g. because it only read the basis set) we set it
01629   // to the number of atoms in the molecule.
01630   // XXX This is kind of dangerous: If you load a basis set
01631   // on top of a multimillion atom structure then a basis
01632   // will be added to each of the atoms whic cost a lot of
01633   // memory!
01634   if (!numatoms) numatoms = mol->nAtoms;
01635   mol->qm_data = new QMData(numatoms,
01636                             metadata.num_basis_funcs,
01637                             metadata.num_shells,
01638                             metadata.wavef_size);
01639   //mol->qm_data->nintcoords = metadata.nintcoords;
01640 
01641   // We need to keep a pointer to the QMData object
01642   // to be used in next() when we are sorting the
01643   // wavefunction coefficients for the current timestep.
01644   qm_data = mol->qm_data;
01645 #endif
01646 
01647   molfile_qm_t *qmdata = (molfile_qm_t *) calloc(1, sizeof(molfile_qm_t));
01648 
01649 #if vmdplugin_ABIVERSION > 11
01650   // Allocate memory for the arrays:
01651   if (metadata.num_basis_atoms) {
01652     qmdata->basis.num_shells_per_atom = new int[metadata.num_basis_atoms];
01653     qmdata->basis.atomic_number       = new int[metadata.num_basis_atoms];
01654     qmdata->basis.num_prim_per_shell  = new int[metadata.num_shells];
01655     qmdata->basis.basis            = new float[2*metadata.num_basis_funcs];
01656     qmdata->basis.shell_types      = new int[metadata.num_shells];
01657     qmdata->basis.angular_momentum = new int[3*metadata.wavef_size];
01658   }
01659 
01660   if (metadata.nimag)
01661     qmdata->hess.imag_modes = new int[metadata.nimag];
01662 
01663   if (metadata.have_normalmodes) {
01664     qmdata->hess.normalmodes = new float[metadata.ncart*metadata.ncart];
01665     qmdata->hess.wavenumbers = new float[metadata.ncart];
01666     qmdata->hess.intensities = new float[metadata.ncart];
01667   }
01668 
01669   if (metadata.have_carthessian)
01670     qmdata->hess.carthessian = new double[metadata.ncart*metadata.ncart];
01671 
01672   if (metadata.have_inthessian)
01673     qmdata->hess.inthessian = new double[metadata.nintcoords*metadata.nintcoords];
01674 
01675 //   if (metadata.have_esp) {
01676 //     qmdata->run.esp_charges = new double[numatoms];
01677 //   }
01678 //   else
01679 //     qmdata->run.esp_charges = NULL;
01680 #endif
01681 
01682   // All necessary arrays are allocated.
01683   // Now get the data from the plugin:
01684   plugin->read_qm_rundata(rv, qmdata);
01685 
01686 #if vmdplugin_ABIVERSION > 11
01687   // Copy data from molfile_plugin structs into VMD's data structures.
01688 
01689   if (metadata.have_sysinfo) {
01690     //mol->qm_data->num_orbitals_A = qmdata->run.num_orbitals_A;
01691     //mol->qm_data->num_orbitals_B = qmdata->run.num_orbitals_B;
01692     mol->qm_data->nproc  = qmdata->run.nproc;
01693 #if vmdplugin_ABIVERSION > 12
01694     mol->qm_data->memory = qmdata->run.memory;
01695 #else
01696     mol->qm_data->memory = 0; // the older ABI used an unformatted string
01697 #endif
01698 
01699     // We need to translate between the macros used in the plugins
01700     // and the one ones in VMD, here so that they can be independent
01701     // and we don't have to include molfile_plugin.h anywhere else
01702     // in VMD.
01703     switch (qmdata->run.scftype) {
01704     case MOLFILE_SCFTYPE_NONE:
01705       mol->qm_data->scftype = SCFTYPE_NONE;
01706       break;
01707     case MOLFILE_SCFTYPE_RHF:
01708       mol->qm_data->scftype = SCFTYPE_RHF;
01709       break;
01710     case MOLFILE_SCFTYPE_UHF:
01711       mol->qm_data->scftype = SCFTYPE_UHF;
01712       break;
01713     case MOLFILE_SCFTYPE_ROHF:
01714       mol->qm_data->scftype = SCFTYPE_ROHF;
01715       break;
01716     case MOLFILE_SCFTYPE_GVB:
01717       mol->qm_data->scftype = SCFTYPE_GVB;
01718       break;
01719     case MOLFILE_SCFTYPE_MCSCF:
01720       mol->qm_data->scftype = SCFTYPE_MCSCF;
01721       break;
01722     case MOLFILE_SCFTYPE_FF:
01723       mol->qm_data->scftype = SCFTYPE_FF;
01724       break;
01725     default:
01726       mol->qm_data->scftype = SCFTYPE_UNKNOWN;
01727     }
01728 
01729     switch (qmdata->run.runtype) {
01730     case MOLFILE_RUNTYPE_ENERGY:
01731       mol->qm_data->runtype = RUNTYPE_ENERGY;
01732       break;
01733     case MOLFILE_RUNTYPE_OPTIMIZE:
01734       mol->qm_data->runtype = RUNTYPE_OPTIMIZE;
01735       break;
01736     case MOLFILE_RUNTYPE_SADPOINT:
01737       mol->qm_data->runtype = RUNTYPE_SADPOINT;
01738       break;
01739     case MOLFILE_RUNTYPE_HESSIAN:
01740       mol->qm_data->runtype = RUNTYPE_HESSIAN;
01741       break;
01742     case MOLFILE_RUNTYPE_SURFACE:
01743       mol->qm_data->runtype = RUNTYPE_SURFACE;
01744       break;
01745     case MOLFILE_RUNTYPE_GRADIENT:
01746       mol->qm_data->runtype = RUNTYPE_GRADIENT;
01747       break;
01748     case MOLFILE_RUNTYPE_MEX:
01749       mol->qm_data->runtype = RUNTYPE_MEX;
01750       break;
01751     case MOLFILE_RUNTYPE_DYNAMICS:
01752       mol->qm_data->runtype = RUNTYPE_DYNAMICS;
01753       break;
01754     case MOLFILE_RUNTYPE_PROPERTIES:
01755       mol->qm_data->runtype = RUNTYPE_PROPERTIES;
01756       break;
01757     default:
01758       mol->qm_data->runtype = RUNTYPE_UNKNOWN;
01759     }
01760 
01761     switch (qmdata->run.status) {
01762     case MOLFILE_QMSTATUS_OPT_CONV:
01763       mol->qm_data->status = QMSTATUS_OPT_CONV;
01764       break;
01765     case MOLFILE_QMSTATUS_OPT_NOT_CONV:
01766       mol->qm_data->status = QMSTATUS_OPT_NOT_CONV;
01767       break;
01768     case MOLFILE_QMSTATUS_SCF_NOT_CONV:
01769       mol->qm_data->status = QMSTATUS_SCF_NOT_CONV;
01770       break;
01771     case MOLFILE_QMSTATUS_FILE_TRUNCATED:
01772       mol->qm_data->status = QMSTATUS_FILE_TRUNCATED;
01773       break;
01774     default:
01775       mol->qm_data->status = QMSTATUS_UNKNOWN;
01776     }
01777 
01778     // Run data:
01779     SAFESTRNCPY(mol->qm_data->version_string, qmdata->run.version_string);
01780     SAFESTRNCPY(mol->qm_data->runtitle, qmdata->run.runtitle);
01781     SAFESTRNCPY(mol->qm_data->geometry, qmdata->run.geometry);
01782   }
01783 
01784   if (metadata.have_sysinfo) {
01785     // Initialize total charge, multiplicity, number of electrons,
01786     // number of occupied orbitals.
01787     // Note that mol->qm_data->scftyp must have been
01788     // assign before.
01789     mol->qm_data->init_electrons(mol, qmdata->run.totalcharge);
01790   }
01791 
01792   // Populate basis set data and organize them into
01793   // hierarcical data structures.
01794   if (!mol->qm_data->init_basis(mol, metadata.num_basis_atoms,
01795                                 qmdata->run.basis_string,
01796                                 qmdata->basis.basis,
01797                                 qmdata->basis.atomic_number,
01798                                 qmdata->basis.num_shells_per_atom,
01799                                 qmdata->basis.num_prim_per_shell,
01800                                 qmdata->basis.shell_types)) {
01801     msgWarn << "Incomplete basis set info in QM data."
01802            << sendmsg;
01803   }
01804 
01805   // Exponents of angular momenta in wave function
01806   if (metadata.wavef_size) {
01807     mol->qm_data->set_angular_momenta(qmdata->basis.angular_momentum);
01808   }
01809 
01810 
01811   // Hessian data:
01812   if (metadata.have_carthessian) {
01813     mol->qm_data->set_carthessian(metadata.ncart, qmdata->hess.carthessian);
01814   }
01815   
01816   if (metadata.have_inthessian) {
01817     mol->qm_data->set_inthessian(metadata.nintcoords, qmdata->hess.inthessian);
01818   }
01819 
01820   if (metadata.have_normalmodes) {
01821     mol->qm_data->set_normalmodes(metadata.ncart, qmdata->hess.normalmodes);
01822     mol->qm_data->set_wavenumbers(metadata.ncart, qmdata->hess.wavenumbers);
01823     mol->qm_data->set_intensities(metadata.ncart, qmdata->hess.intensities);
01824   }
01825 
01826   if (metadata.nimag) {
01827     mol->qm_data->set_imagmodes(metadata.nimag, qmdata->hess.imag_modes);
01828   }
01829 
01830   // Cleanup the arrays we needed to get the data from the plugin.
01831   if (metadata.num_basis_atoms) {
01832     delete [] qmdata->basis.num_shells_per_atom;
01833     delete [] qmdata->basis.atomic_number;
01834     delete [] qmdata->basis.num_prim_per_shell;
01835     delete [] qmdata->basis.basis;
01836     delete [] qmdata->basis.shell_types;
01837     delete [] qmdata->basis.angular_momentum;
01838   }
01839   delete [] qmdata->hess.carthessian;
01840   delete [] qmdata->hess.inthessian;
01841   delete [] qmdata->hess.normalmodes;
01842   delete [] qmdata->hess.wavenumbers;
01843   delete [] qmdata->hess.intensities;
01844   delete [] qmdata->hess.imag_modes;
01845   free(qmdata);
01846 #endif
01847 
01848   return MOLFILE_SUCCESS;
01849 }
01850 
01851 
01852 int MolFilePlugin::write_volumetric(Molecule *m, int set) {
01853   if (set < 0 || set > m->num_volume_data()) {
01854     msgErr << "Bogus setid passed to write_volumetric: " << set
01855            << sendmsg;
01856     return MOLFILE_SUCCESS;
01857   } 
01858 
01859   const VolumetricData *v = m->get_volume_data(set); 
01860 
01861   molfile_volumetric_t volmeta;
01862 
01863   // SAFESTRNCPY(volmeta.dataname, v->name); 
01864   int n = ((sizeof(volmeta.dataname) < strlen(v->name)+1) ? 
01865             sizeof(volmeta.dataname) : strlen(v->name)+1);
01866   strncpy(volmeta.dataname, v->name, n);
01867 
01868   for (int i=0; i<3; i++) {
01869       volmeta.origin[i] = (float)v->origin[i];
01870       volmeta.xaxis[i] = (float)v->xaxis[i];
01871       volmeta.yaxis[i] = (float)v->yaxis[i];
01872       volmeta.zaxis[i] = (float)v->zaxis[i];
01873   }
01874   volmeta.xsize = v->xsize;
01875   volmeta.ysize = v->ysize;
01876   volmeta.zsize = v->zsize;
01877   volmeta.has_color = 0;
01878  
01879   float *datablock = v->data;
01880   float *colorblock = NULL;
01881 
01882   plugin->write_volumetric_data(wv, &volmeta, datablock, colorblock);
01883 
01884   return MOLFILE_SUCCESS;
01885 }
01886 #endif
01887 

Generated on Sat May 26 01:48:12 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002