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

colvarproxy_vmd.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
00009 
00010 #include <tcl.h>
00011 
00012 #include "VMDApp.h"
00013 #include "DrawMolecule.h"
00014 #include "MoleculeList.h"
00015 #include "Timestep.h"
00016 #include "Residue.h"
00017 #include "Inform.h"
00018 #include "utilities.h"
00019 
00020 #include "colvarmodule.h"
00021 #include "colvarscript.h"
00022 #include "colvaratoms.h"
00023 #include "colvarscript.h"
00024 #include "colvarproxy.h"
00025 #include "colvarproxy_vmd.h"
00026 
00027 
00028 namespace {
00029   // Keep pointers to relevant runtime objects
00030   VMDApp *colvars_vmd_ptr = NULL;
00031   colvarproxy_vmd *colvarproxy_vmd_ptr = NULL;
00032 }
00033 
00034 
00035 // Copy of declaration from colvarscript.cpp (this alone doesn't warrant a
00036 // new header file)
00037 // COLVARS_TCL is defined when relevant in colvarproxy_tcl.h, included via colvarproxy.h
00038 #ifdef COLVARS_TCL
00039 extern "C" int tcl_run_colvarscript_command(ClientData clientData,
00040                                             Tcl_Interp *interp_in,
00041                                             int objc, Tcl_Obj *const objv[]);
00042 #endif
00043 
00044 
00045 int tcl_colvars(ClientData clientData, Tcl_Interp *interp,
00046                 int objc, Tcl_Obj *const objv[])
00047 {
00048   // Get pointer to VMD object
00049   if (colvars_vmd_ptr == NULL) {
00050     colvars_vmd_ptr = (VMDApp *) clientData;
00051   }
00052   return tcl_run_colvarscript_command(clientData, interp, objc, objv);
00053 }
00054 
00055 
00056 int tcl_colvars_vmd_init(Tcl_Interp *interp, int molid_input)
00057 {
00058   VMDApp *const vmd = colvars_vmd_ptr;
00059   int molid = molid_input == -(1<<16) ? vmd->molecule_top() : molid_input;
00060   if (vmd->molecule_valid_id(molid)) {
00061     colvarproxy_vmd_ptr = new colvarproxy_vmd(interp, vmd, molid);
00062     return (cvm::get_error() == COLVARS_OK) ? TCL_OK : TCL_ERROR;
00063   } else {
00064     Tcl_SetResult(interp, (char *) "Error: molecule not found.",
00065                   TCL_STATIC);
00066     return TCL_ERROR;
00067   }
00068 }
00069 
00070 
00071 colvarproxy_vmd::colvarproxy_vmd(Tcl_Interp *interp, VMDApp *v, int molid)
00072   : vmd(v),
00073     vmdmolid(molid),
00074 #if defined(VMDTKCON)
00075     msgColvars("colvars: ", VMDCON_INFO)
00076 #else
00077     msgColvars("colvars: ")
00078 #endif
00079 {
00080   version_int = get_version_from_string(COLVARPROXY_VERSION);
00081   b_simulation_running = false;
00082 
00083   // both fields are taken from data structures already available
00084   updated_masses_ = updated_charges_ = true;
00085 
00086   // Do we have scripts?
00087   // For now colvars depend on Tcl, but this may not always be the case
00088   // in the future
00089 #if defined(VMDTCL)
00090   have_scripts = true;
00091   // Need to set this before constructing colvarmodule, which creates colvarscript object
00092   set_tcl_interp(interp);
00093 #else
00094   have_scripts = false;
00095 #endif
00096 
00097   colvars = new colvarmodule(this);
00098   cvm::log("Using VMD interface, version "+
00099            cvm::to_str(COLVARPROXY_VERSION)+".\n");
00100 
00101   colvars->cite_feature("VMD engine");
00102   colvars->cite_feature("Colvars-VMD interface (command line)");
00103 
00104   colvars->cv_traj_freq = 0; // I/O will be handled explicitly
00105   colvars->restart_out_freq = 0;
00106   cvm::rotation::monitor_crossings = false; // Avoid unnecessary error messages
00107 
00108   // Default to VMD's native unit system, but do not set the units string
00109   // to preserve the native workflow of VMD / NAMD / LAMMPS-real
00110   angstrom_value_ = 1.;
00111   kcal_mol_value_ = 1.;
00112 
00113   colvars->setup_input();
00114   colvars->setup_output();
00115 
00116   // set the same seed as in Measure.C
00117   vmd_srandom(38572111);
00118 
00119   colvarproxy_vmd::setup();
00120 }
00121 
00122 
00123 colvarproxy_vmd::~colvarproxy_vmd()
00124 {}
00125 
00126 
00127 int colvarproxy_vmd::request_deletion()
00128 {
00129   b_delete_requested = true;
00130   return COLVARS_OK;
00131 }
00132 
00133 
00134 int colvarproxy_vmd::setup()
00135 {
00136   int error_code = colvarproxy::setup();
00137   vmdmol = vmd->moleculeList->mol_from_id(vmdmolid);
00138   if (vmdmol) {
00139     set_frame(vmdmol->frame());
00140   } else {
00141     error("Error: requested molecule ("+cvm::to_str(vmdmolid)+") does not exist.\n");
00142     return COLVARS_ERROR;
00143   }
00144 
00145   return colvars->update_engine_parameters();
00146 }
00147 
00148 
00149 cvm::real colvarproxy_vmd::rand_gaussian()
00150 {
00151   return vmd_random_gaussian();
00152 }
00153 
00154 
00155 int colvarproxy_vmd::set_unit_system(std::string const &units_in, bool check_only)
00156 {
00157   // if check_only is specified, just test for compatibility
00158   // cvolvarmodule does that if new units are requested while colvars are already defined
00159   if (check_only) {
00160     if ((units != "" && units_in != units) || (units == "" && units_in != "real")) {
00161       cvm::error("Specified unit system \"" + units_in + "\" is incompatible with previous setting \""
00162                   + units + "\".\nReset the Colvars Module or delete all variables to change the unit.\n");
00163       return COLVARS_ERROR;
00164     } else {
00165       return COLVARS_OK;
00166     }
00167   }
00168 
00169   if (units_in == "real") {
00170     angstrom_value_ = 1.;
00171     kcal_mol_value_ = 1.;
00172   } else if (units_in == "metal") {
00173     angstrom_value_ = 1.;
00174     kcal_mol_value_ = 0.0433641017; // eV
00175     // inverse of LAMMPS value is 1/23.060549 = .043364102
00176   } else if (units_in == "electron") {
00177     angstrom_value_ = 1.88972612;    // Bohr
00178     kcal_mol_value_ = 0.00159360144; // Hartree
00179   } else if (units_in == "gromacs") {
00180     angstrom_value_ = 0.1;    // nm
00181     kcal_mol_value_ = 4.184;  // kJ/mol
00182   } else {
00183     cvm::error("Unknown unit system specified: \"" + units_in + "\". Supported are real, metal, electron, and gromacs.\n");
00184     return COLVARS_ERROR;
00185   }
00186 
00187   units = units_in;
00188   return COLVARS_OK;
00189 }
00190 
00191 
00192 int colvarproxy_vmd::update_input()
00193 {
00194   colvarproxy::update_input();
00195 
00196   int error_code = COLVARS_OK;
00197 
00198   // Check that our parent molecule still exists
00199   if (vmd->moleculeList->mol_from_id(vmdmolid) == NULL) {
00200     error("Error: requested molecule ("+cvm::to_str(vmdmolid)+") does not exist.\n");
00201     return COLVARS_ERROR;
00202   }
00203   error_code |= update_atomic_properties();
00204 
00205   size_t i;
00206   // We're not applying any forces but they can be tracked through [cv getatomappliedforces]
00207   // Clear before updating Module
00208   for (i = 0; i < atoms_new_colvar_forces.size(); i++) {
00209     atoms_new_colvar_forces[i].reset();
00210   }
00211 
00212   // Do we still have a valid frame?
00213   if (error_code || vmdmol->get_frame(vmdmol_frame) == NULL) {
00214     error_code |= COLVARS_NO_SUCH_FRAME;
00215     return error_code;
00216   }
00217 
00218   // copy positions in the internal arrays
00219   float *vmdpos = (vmdmol->get_frame(vmdmol_frame))->pos;
00220   for (i = 0; i < atoms_positions.size(); i++) {
00221     atoms_positions[i] = cvm::atom_pos(angstrom_to_internal(vmdpos[atoms_ids[i]*3+0]),
00222                                        angstrom_to_internal(vmdpos[atoms_ids[i]*3+1]),
00223                                        angstrom_to_internal(vmdpos[atoms_ids[i]*3+2]));
00224   }
00225 
00226 
00227   Timestep const *ts = vmdmol->get_frame(vmdmol_frame);
00228   {
00229     // Get lattice vectors
00230     float A[3];
00231     float B[3];
00232     float C[3];
00233     ts->get_transform_vectors(A, B, C);
00234     unit_cell_x.set(angstrom_to_internal(A[0]), angstrom_to_internal(A[1]), angstrom_to_internal(A[2]));
00235     unit_cell_y.set(angstrom_to_internal(B[0]), angstrom_to_internal(B[1]), angstrom_to_internal(B[2]));
00236     unit_cell_z.set(angstrom_to_internal(C[0]), angstrom_to_internal(C[1]), angstrom_to_internal(C[2]));
00237   }
00238 
00239   if (ts->a_length + ts->b_length + ts->c_length < 1.0e-6) {
00240     boundaries_type = boundaries_non_periodic;
00241     reset_pbc_lattice();
00242   } else if ((ts->a_length > 1.0e-6) &&
00243              (ts->b_length > 1.0e-6) &&
00244              (ts->c_length > 1.0e-6)) {
00245     if (((ts->alpha-90.0)*(ts->alpha-90.0)) +
00246         ((ts->beta-90.0)*(ts->beta-90.0)) +
00247         ((ts->gamma-90.0)*(ts->gamma-90.0)) < 1.0e-6) {
00248       boundaries_type = boundaries_pbc_ortho;
00249     } else {
00250       boundaries_type = boundaries_pbc_triclinic;
00251     }
00252     colvarproxy_system::update_pbc_lattice();
00253   } else {
00254     boundaries_type = boundaries_unsupported;
00255   }
00256 
00257   return error_code;
00258 }
00259 
00260 
00261 void colvarproxy_vmd::add_energy(cvm::real energy)
00262 {
00263 }
00264 
00265 
00266 int colvarproxy_vmd::update_atomic_properties()
00267 {
00268   float const *masses = vmdmol->mass();
00269   float const *charges = vmdmol->charge();
00270 
00271   int error_code = COLVARS_OK;
00272 
00273   if (masses == NULL) {
00274     error("Error: masses are undefined for the molecule being used.\n");
00275     error_code |= COLVARS_BUG_ERROR;
00276   } else {
00277     for (size_t i = 0; i < atoms_ids.size(); i++) {
00278       atoms_masses[i]  = masses[atoms_ids[i]];
00279     }
00280   }
00281 
00282   if (charges == NULL) {
00283     error("Error: charges are undefined for the molecule being used.\n");
00284     error_code |= COLVARS_BUG_ERROR;
00285   } else {
00286     for (size_t i = 0; i < atoms_ids.size(); i++) {
00287       atoms_charges[i] = charges[atoms_ids[i]];
00288     }
00289   }
00290 
00291   return error_code;
00292 }
00293 
00294 
00295 void colvarproxy_vmd::request_total_force(bool yesno)
00296 {
00297   if ((yesno == true) && (total_force_requested == false)) {
00298     cvm::log("Warning: a bias requested total forces, which are undefined in VMD.  "
00299              "This is only meaningful when analyzing a simulation where these were used, "
00300              "provided that a state file is loaded.\n");
00301   }
00302   total_force_requested = yesno;
00303 }
00304 
00305 
00306 void colvarproxy_vmd::log(std::string const &message)
00307 {
00308   std::istringstream is(message);
00309   std::string line;
00310   while (std::getline(is, line)) {
00311     msgColvars << line.c_str() << sendmsg;
00312   }
00313 }
00314 
00315 
00316 void colvarproxy_vmd::error(std::string const &message)
00317 {
00318   add_error_msg(message);
00319   log(message);
00320 }
00321 
00322 
00323 int colvarproxy_vmd::get_molid(int &molid)
00324 {
00325   molid = vmdmolid;
00326   return COLVARS_OK;
00327 }
00328 
00329 
00330 int colvarproxy_vmd::get_frame(long int &f)
00331 {
00332   f = vmdmol_frame;
00333   return COLVARS_OK;
00334 }
00335 
00336 
00337 int colvarproxy_vmd::set_frame(long int f)
00338 {
00339   if (vmdmol->get_frame(f) != NULL) {
00340 
00341     vmdmol_frame = f;
00342     colvars->it = f;
00343 
00344     update_input();
00345 
00346     return COLVARS_OK;
00347   } else {
00348     return COLVARS_NO_SUCH_FRAME;
00349   }
00350 }
00351 
00352 
00353 void colvarproxy_vmd::init_tcl_pointers()
00354 {
00355 #ifdef VMDTCL
00356   // Do nothing (when constructing colvarproxy), this will be set by colvarproxy_vmd constructor
00357 #else
00358   colvarproxy::init_tcl_pointers(); // Create dedicated interpreter
00359 #endif
00360 }
00361 
00362 
00363 // Callback functions
00364 
00365 #ifdef VMDTCL
00366 
00367 int colvarproxy_vmd::run_force_callback()
00368 {
00369   return colvarproxy::tcl_run_force_callback();
00370 }
00371 
00372 int colvarproxy_vmd::run_colvar_callback(
00373                          std::string const &name,
00374                          std::vector<const colvarvalue *> const &cvc_values,
00375                          colvarvalue &value)
00376 {
00377   return colvarproxy::tcl_run_colvar_callback(name, cvc_values, value);
00378 }
00379 
00380 int colvarproxy_vmd::run_colvar_gradient_callback(
00381                          std::string const &name,
00382                          std::vector<const colvarvalue *> const &cvc_values,
00383                          std::vector<cvm::matrix2d<cvm::real> > &gradient)
00384 {
00385   return colvarproxy::tcl_run_colvar_gradient_callback(name, cvc_values,
00386                                                        gradient);
00387 }
00388 #endif
00389 
00390 
00391 enum e_pdb_field {
00392   e_pdb_none,
00393   e_pdb_occ,
00394   e_pdb_beta,
00395   e_pdb_x,
00396   e_pdb_y,
00397   e_pdb_z,
00398   e_pdb_ntot
00399 };
00400 
00401 e_pdb_field pdb_field_str2enum(std::string const &pdb_field_str)
00402 {
00403   e_pdb_field pdb_field = e_pdb_none;
00404 
00405   if (colvarparse::to_lower_cppstr(pdb_field_str) ==
00406       colvarparse::to_lower_cppstr("O")) {
00407     pdb_field = e_pdb_occ;
00408   }
00409 
00410   if (colvarparse::to_lower_cppstr(pdb_field_str) ==
00411       colvarparse::to_lower_cppstr("B")) {
00412     pdb_field = e_pdb_beta;
00413   }
00414 
00415   if (colvarparse::to_lower_cppstr(pdb_field_str) ==
00416       colvarparse::to_lower_cppstr("X")) {
00417     pdb_field = e_pdb_x;
00418   }
00419 
00420   if (colvarparse::to_lower_cppstr(pdb_field_str) ==
00421       colvarparse::to_lower_cppstr("Y")) {
00422     pdb_field = e_pdb_y;
00423   }
00424 
00425   if (colvarparse::to_lower_cppstr(pdb_field_str) ==
00426       colvarparse::to_lower_cppstr("Z")) {
00427     pdb_field = e_pdb_z;
00428   }
00429 
00430   if (pdb_field == e_pdb_none) {
00431     cvm::error("Error: unsupported PDB field, \""+
00432                      pdb_field_str+"\".\n");
00433   }
00434 
00435   return pdb_field;
00436 }
00437 
00438 
00439 int colvarproxy_vmd::load_coords(char const *pdb_filename,
00440                                  std::vector<cvm::atom_pos> &pos,
00441                                  const std::vector<int> &indices,
00442                                  std::string const &pdb_field_str,
00443                                  double const pdb_field_value)
00444 {
00445   if (pdb_field_str.size() == 0 && indices.size() == 0) {
00446     cvm::error("Bug alert: either PDB field should be defined or list of "
00447                "atom IDs should be available when loading atom coordinates!\n",
00448                COLVARS_BUG_ERROR);
00449     return COLVARS_ERROR;
00450   }
00451 
00452   e_pdb_field pdb_field_index = e_pdb_none;
00453   bool const use_pdb_field = (pdb_field_str.size() > 0);
00454   if (use_pdb_field) {
00455     pdb_field_index = pdb_field_str2enum(pdb_field_str);
00456   }
00457 
00458   // next index to be looked up in PDB file (if list is supplied)
00459   std::vector<int>::const_iterator current_index = indices.begin();
00460 
00461   FileSpec *tmpspec = new FileSpec();
00462   tmpspec->autobonds = 0;
00463   int tmpmolid = vmd->molecule_load(-1, pdb_filename, "pdb", tmpspec);
00464   delete tmpspec;
00465   if (tmpmolid < 0) {
00466     cvm::error("Error: VMD could not read file \""+std::string(pdb_filename)+"\".\n",
00467                COLVARS_FILE_ERROR);
00468     return COLVARS_ERROR;
00469   }
00470   DrawMolecule *tmpmol = vmd->moleculeList->mol_from_id(tmpmolid);
00471 
00472   vmd->molecule_make_top(vmdmolid);
00473   size_t const pdb_natoms = tmpmol->nAtoms;
00474 
00475   if (pos.size() != pdb_natoms) {
00476 
00477     bool const pos_allocated = (pos.size() > 0);
00478 
00479     size_t ipos = 0, ipdb = 0;
00480     for ( ; ipdb < pdb_natoms; ipdb++) {
00481 
00482       if (use_pdb_field) {
00483         // PDB field mode: skip atoms with wrong value in PDB field
00484         double atom_pdb_field_value = 0.0;
00485 
00486         switch (pdb_field_index) {
00487         case e_pdb_occ:
00488           atom_pdb_field_value = (tmpmol->occupancy())[ipdb];
00489           break;
00490         case e_pdb_beta:
00491           atom_pdb_field_value = (tmpmol->beta())[ipdb];
00492           break;
00493         case e_pdb_x:
00494           atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3];
00495           break;
00496         case e_pdb_y:
00497           atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3+1];
00498           break;
00499         case e_pdb_z:
00500           atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3+2];
00501           break;
00502         default:
00503           break;
00504         }
00505 
00506         if ( (pdb_field_value) &&
00507              (atom_pdb_field_value != pdb_field_value) ) {
00508           continue;
00509         } else if (atom_pdb_field_value == 0.0) {
00510           continue;
00511         }
00512 
00513       } else {
00514         // Atom ID mode: use predefined atom IDs from the atom group
00515         if (((int)ipdb) != *current_index) {
00516           // Skip atoms not in the list
00517           continue;
00518         } else {
00519           current_index++;
00520         }
00521       }
00522 
00523       if (!pos_allocated) {
00524         pos.push_back(cvm::atom_pos(0.0, 0.0, 0.0));
00525       } else if (ipos >= pos.size()) {
00526         cvm::error("Error: the PDB file \""+
00527                    std::string(pdb_filename)+
00528                    "\" contains coordinates for "
00529                    "more atoms than needed.\n", COLVARS_INPUT_ERROR);
00530         return COLVARS_ERROR;
00531       }
00532 
00533       pos[ipos] = cvm::atom_pos(angstrom_to_internal((tmpmol->get_frame(0)->pos)[ipdb*3]),
00534                                 angstrom_to_internal((tmpmol->get_frame(0)->pos)[ipdb*3+1]),
00535                                 angstrom_to_internal((tmpmol->get_frame(0)->pos)[ipdb*3+2]));
00536       ipos++;
00537       if (!use_pdb_field && current_index == indices.end())
00538         break;
00539     }
00540 
00541     if (ipos < pos.size() || (!use_pdb_field && current_index != indices.end())) {
00542       size_t n_requested = use_pdb_field ? pos.size() : indices.size();
00543       cvm::error("Error: number of matching records in the PDB file \""+
00544                  std::string(pdb_filename)+"\" ("+cvm::to_str(ipos)+
00545                  ") does not match the number of requested coordinates ("+
00546                  cvm::to_str(n_requested)+").\n", COLVARS_INPUT_ERROR);
00547       return COLVARS_ERROR;
00548     }
00549   } else {
00550 
00551     // when the PDB contains exactly the number of atoms of the array,
00552     // ignore the fields and just read coordinates
00553     for (size_t ia = 0; ia < pos.size(); ia++) {
00554       pos[ia] = cvm::atom_pos(angstrom_to_internal((tmpmol->get_frame(0)->pos)[ia*3]),
00555                               angstrom_to_internal((tmpmol->get_frame(0)->pos)[ia*3+1]),
00556                               angstrom_to_internal((tmpmol->get_frame(0)->pos)[ia*3+2]));
00557     }
00558   }
00559 
00560   vmd->molecule_delete(tmpmolid);
00561   return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
00562 }
00563 
00564 
00565 int colvarproxy_vmd::load_atoms(char const *pdb_filename,
00566                                 cvm::atom_group &atoms,
00567                                 std::string const &pdb_field_str,
00568                                 double const pdb_field_value)
00569 {
00570   if (pdb_field_str.size() == 0) {
00571     cvm::log("Error: must define which PDB field to use "
00572              "in order to define atoms from a PDB file.\n");
00573     cvm::set_error_bits(COLVARS_INPUT_ERROR);
00574     return COLVARS_ERROR;
00575   }
00576 
00577   FileSpec *tmpspec = new FileSpec();
00578   tmpspec->autobonds = 0;
00579   int tmpmolid = vmd->molecule_load(-1, pdb_filename, "pdb", tmpspec);
00580   delete tmpspec;
00581 
00582   if (tmpmolid < 0) {
00583     cvm::error("Error: VMD could not read file \""+std::string(pdb_filename)+"\".\n",
00584                COLVARS_FILE_ERROR);
00585     return COLVARS_ERROR;
00586   }
00587   DrawMolecule *tmpmol = vmd->moleculeList->mol_from_id(tmpmolid);
00588 
00589   vmd->molecule_make_top(vmdmolid);
00590   size_t const pdb_natoms = tmpmol->nAtoms;
00591 
00592   e_pdb_field pdb_field_index = pdb_field_str2enum(pdb_field_str);
00593 
00594   for (size_t ipdb = 0; ipdb < pdb_natoms; ipdb++) {
00595 
00596     double atom_pdb_field_value = 0.0;
00597 
00598     switch (pdb_field_index) {
00599     case e_pdb_occ:
00600       atom_pdb_field_value = (tmpmol->occupancy())[ipdb];
00601       break;
00602     case e_pdb_beta:
00603       atom_pdb_field_value = (tmpmol->beta())[ipdb];
00604       break;
00605     case e_pdb_x:
00606       atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3];
00607       break;
00608     case e_pdb_y:
00609       atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3+1];
00610       break;
00611     case e_pdb_z:
00612       atom_pdb_field_value = (tmpmol->get_frame(0)->pos)[ipdb*3+2];
00613       break;
00614     default:
00615       break;
00616     }
00617 
00618     if ( (pdb_field_value) &&
00619          (atom_pdb_field_value != pdb_field_value) ) {
00620       continue;
00621     } else if (atom_pdb_field_value == 0.0) {
00622       continue;
00623     }
00624 
00625     atoms.add_atom(cvm::atom(ipdb+1));
00626   }
00627 
00628   vmd->molecule_delete(tmpmolid);
00629   return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
00630 }
00631 
00632 
00633 
00634 int colvarproxy_vmd::check_atom_id(int atom_number)
00635 {
00636   // VMD internal numbering starts from zero
00637   int const aid(atom_number-1);
00638 
00639   if (cvm::debug())
00640     cvm::log("Adding atom "+cvm::to_str(aid+1)+
00641              " for collective variables calculation.\n");
00642 
00643   if ( (aid < 0) || (aid >= vmdmol->nAtoms) ) {
00644     cvm::error("Error: invalid atom number specified, "+
00645                cvm::to_str(atom_number)+"\n");
00646     return COLVARS_INPUT_ERROR;
00647   }
00648 
00649   return aid;
00650 }
00651 
00652 
00653 int colvarproxy_vmd::init_atom(int atom_number)
00654 {
00655   // save time by checking first whether this atom has been requested before
00656   // (this is more common than a non-valid atom number)
00657   int aid = (atom_number-1);
00658 
00659   for (size_t i = 0; i < atoms_ids.size(); i++) {
00660     if (atoms_ids[i] == aid) {
00661       // this atom id was already recorded
00662       atoms_refcount[i] += 1;
00663       return i;
00664     }
00665   }
00666 
00667   aid = check_atom_id(atom_number);
00668 
00669   if (aid < 0) {
00670     return COLVARS_INPUT_ERROR;
00671   }
00672 
00673   int const index = add_atom_slot(aid);
00674 
00675   float const *masses = vmdmol->mass();
00676   float const *charges = vmdmol->charge();
00677   atoms_masses[index] = masses[aid];
00678   atoms_charges[index] = charges[aid];
00679 
00680   return index;
00681 }
00682 
00683 
00684 int colvarproxy_vmd::check_atom_id(cvm::residue_id const &resid,
00685                                    std::string const     &atom_name,
00686                                    std::string const     &segment_id)
00687 {
00688   int aid = -1;
00689   for (int ir = 0; ir < vmdmol->nResidues; ir++) {
00690     Residue *vmdres = vmdmol->residue(ir);
00691     if (vmdres->resid == resid) {
00692       for (int ia = 0; ia < vmdres->atoms.num(); ia++) {
00693         int const resaid = vmdres->atoms[ia];
00694         std::string const sel_segname((vmdmol->segNames).name(vmdmol->atom(resaid)->segnameindex));
00695         std::string const sel_atom_name((vmdmol->atomNames).name(vmdmol->atom(resaid)->nameindex));
00696         if ( ((segment_id.size() == 0) || (segment_id == sel_segname)) &&
00697              (atom_name == sel_atom_name) ) {
00698           aid = resaid;
00699           break;
00700         }
00701       }
00702     }
00703     if (aid >= 0) break;
00704   }
00705 
00706 
00707   if (aid < 0) {
00708     cvm::error("Error: could not find atom \""+
00709                atom_name+"\" in residue "+
00710                cvm::to_str(resid)+
00711                ( (segment_id.size()) ?
00712                  (", segment \""+segment_id+"\"") :
00713                  ("") )+
00714                "\n", COLVARS_INPUT_ERROR);
00715     return COLVARS_INPUT_ERROR;
00716   }
00717 
00718   return aid;
00719 }
00720 
00721 
00722 int colvarproxy_vmd::init_atom(cvm::residue_id const &resid,
00723                                std::string const     &atom_name,
00724                                std::string const     &segment_id)
00725 {
00726   int const aid = check_atom_id(resid, atom_name, segment_id);
00727 
00728   for (size_t i = 0; i < atoms_ids.size(); i++) {
00729     if (atoms_ids[i] == aid) {
00730       // this atom id was already recorded
00731       atoms_refcount[i] += 1;
00732       return i;
00733     }
00734   }
00735 
00736   if (cvm::debug())
00737     cvm::log("Adding atom \""+
00738              atom_name+"\" in residue "+
00739              cvm::to_str(resid)+
00740              " (index "+cvm::to_str(aid)+
00741              ") for collective variables calculation.\n");
00742 
00743   int const index = add_atom_slot(aid);
00744 
00745   float const *masses = vmdmol->mass();
00746   float const *charges = vmdmol->charge();
00747   atoms_masses[index] = masses[aid];
00748   atoms_charges[index] = charges[aid];
00749 
00750   return index;
00751 }
00752 
00753 
00754 int colvarproxy_vmd::init_volmap_by_id(int volmap_id)
00755 {
00756   for (size_t i = 0; i < volmaps_ids.size(); i++) {
00757     if (volmaps_ids[i] == volmap_id) {
00758       // this map has already been requested
00759       volmaps_refcount[i] += 1;
00760       return i;
00761     }
00762   }
00763 
00764   int index = -1;
00765 
00766   int error_code = check_volmap_by_id(volmap_id);
00767   if (error_code == COLVARS_OK) {
00768     index = add_volmap_slot(volmap_id);
00769   }
00770 
00771   return index;
00772 }
00773 
00774 
00775 int colvarproxy_vmd::check_volmap_by_id(int volmap_id)
00776 {
00777   if ((volmap_id < 0) || (volmap_id >= vmdmol->num_volume_data())) {
00778     return cvm::error("Error: invalid numeric ID ("+cvm::to_str(volmap_id)+
00779                       ") for map.\n", COLVARS_INPUT_ERROR);
00780   }
00781   return COLVARS_OK;
00782 }
00783 
00784 
00785 void colvarproxy_vmd::clear_volmap(int index)
00786 {
00787   colvarproxy::clear_volmap(index);
00788 }
00789 
00790 
00791 template<int flags>
00792 void colvarproxy_vmd::compute_voldata(VolumetricData const *voldata,
00793                                       cvm::atom_iter atom_begin,
00794                                       cvm::atom_iter atom_end,
00795                                       cvm::real *value,
00796                                       cvm::real *atom_field)
00797 {
00798   int i = 0;
00799   float coord[3], voxcoord[3], grad[3];
00800   cvm::rvector dV(0.0);
00801   cvm::atom_iter ai = atom_begin;
00802   cvm::atom_pos const origin(0.0, 0.0, 0.0);
00803 
00804   for ( ; ai != atom_end; ai++, i++) {
00805 
00806     // Wrap around the origin
00807     cvm::rvector const wrapped_pos = position_distance(origin, ai->pos);
00808     coord[0] = internal_to_angstrom(wrapped_pos.x);
00809     coord[1] = internal_to_angstrom(wrapped_pos.y);
00810     coord[2] = internal_to_angstrom(wrapped_pos.z);
00811 
00812     // Get the coordinates on the grid and check the boundaries
00813     voldata->voxel_coord_from_cartesian_coord(coord, voxcoord, 0);
00814     int const gx = static_cast<int>(voxcoord[0]);
00815     int const gy = static_cast<int>(voxcoord[1]);
00816     int const gz = static_cast<int>(voxcoord[2]);
00817     int valid_coord = 1;
00818     if ((gx < 0) || (gx >= voldata->xsize) ||
00819         (gy < 0) || (gy >= voldata->ysize) ||
00820         (gz < 0) || (gz >= voldata->zsize)) {
00821       valid_coord = 0;
00822     }
00823 
00824     cvm::real const V = valid_coord ?
00825       static_cast<cvm::real>(voldata->voxel_value_interpolate(voxcoord[0],
00826                                                               voxcoord[1],
00827                                                               voxcoord[2])) :
00828       0.0;
00829 
00830     if (flags & volmap_flag_gradients) {
00831       if (valid_coord) {
00832         voldata->voxel_gradient_interpolate(voxcoord, grad);
00833         // Correct the sign of the gradient
00834         dV = cvm::rvector(-1.0*grad[0], -1.0*grad[1], -1.0*grad[2]);
00835       } else {
00836         dV = cvm::rvector(0.0);
00837       }
00838     }
00839 
00840     if (flags & volmap_flag_use_atom_field) {
00841       *value += V * atom_field[i];
00842       if (flags & volmap_flag_gradients) {
00843         ai->grad += atom_field[i] * dV;
00844       }
00845     } else {
00846       *value += V;
00847       if (flags & volmap_flag_gradients) {
00848         ai->grad += dV;
00849       }
00850     }
00851   }
00852 }
00853 
00854 
00855 int colvarproxy_vmd::compute_volmap(int flags,
00856                                     int volmap_id,
00857                                     cvm::atom_iter atom_begin,
00858                                     cvm::atom_iter atom_end,
00859                                     cvm::real *value,
00860                                     cvm::real *atom_field)
00861 {
00862   int error_code = COLVARS_OK;
00863   VolumetricData const *voldata = vmdmol->get_volume_data(volmap_id);
00864   if (voldata != NULL) {
00865 
00866     if (flags & volmap_flag_gradients) {
00867 
00868       if (flags & volmap_flag_use_atom_field) {
00869         int const new_flags = volmap_flag_gradients |
00870           volmap_flag_use_atom_field;
00871         compute_voldata<new_flags>(voldata, atom_begin, atom_end,
00872                                    value, atom_field);
00873       } else {
00874         int const new_flags = volmap_flag_gradients;
00875         compute_voldata<new_flags>(voldata, atom_begin, atom_end,
00876                                    value, NULL);
00877       }
00878 
00879     } else {
00880 
00881       if (flags & volmap_flag_use_atom_field) {
00882         int const new_flags = volmap_flag_use_atom_field;
00883         compute_voldata<new_flags>(voldata, atom_begin, atom_end,
00884                                    value, atom_field);
00885       } else {
00886         int const new_flags = volmap_flag_null;
00887         compute_voldata<new_flags>(voldata, atom_begin, atom_end,
00888                                    value, NULL);
00889       }
00890     }
00891   } else {
00892     // Error message
00893     error_code |=
00894       const_cast<colvarproxy_vmd *>(this)->check_volmap_by_id(volmap_id);
00895   }
00896   return error_code;
00897 }

Generated on Sat Apr 20 02:42:28 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002