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

py_molecule.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 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: py_molecule.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.84 $       $Date: 2022/04/15 20:18:16 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *  Python molecule manipulation interface
00019  ***************************************************************************/
00020 
00021 #include "py_commands.h"
00022 #include <ctype.h>
00023 #include <stdlib.h>
00024 
00025 #include "config.h"
00026 #include "utilities.h"
00027 #include "VMDApp.h"
00028 #include "JString.h"
00029 #include "Molecule.h"
00030 #include "MoleculeList.h"
00031 
00032 // Handle legacy keywords beg, end, skip, with DeprecationWarning
00033 // that is printed out only once
00034 void handle_legacy_keywords(PyObject *kwargs)
00035 {
00036   PyObject *value;
00037   int warn = 0;
00038 
00039   // If no keyword arguments, there will be nothing to do
00040   if (!kwargs)
00041     return;
00042 
00043   // beg -> first
00044   if ((value = PyDict_GetItemString(kwargs, "beg"))) {
00045     PyDict_SetItemString(kwargs, "first", value);
00046     PyDict_DelItemString(kwargs, "beg");
00047     warn = 1;
00048   }
00049 
00050   // end -> last
00051   if ((value = PyDict_GetItemString(kwargs, "end"))) {
00052     PyDict_SetItemString(kwargs, "last", value);
00053     PyDict_DelItemString(kwargs, "end");
00054     warn = 1;
00055   }
00056 
00057   // skip -> stride
00058   if ((value = PyDict_GetItemString(kwargs, "skip"))) {
00059     PyDict_SetItemString(kwargs, "stride", value);
00060     PyDict_DelItemString(kwargs, "skip");
00061     warn = 1;
00062   }
00063 
00064   if (warn) {
00065     PyErr_Warn(PyExc_DeprecationWarning, "beg, end, skip keywords are now "
00066                "first, last, stride");
00067   }
00068 }
00069 
00070 static const char mol_num_doc[] =
00071 "Get the number of loaded molecules\n\n"
00072 "Returns:\n"
00073 "    (int): Number of molecules";
00074 static PyObject* py_mol_num(PyObject *self, PyObject *args)
00075 {
00076   VMDApp *app;
00077   if (!(app = get_vmdapp()))
00078     return NULL;
00079 
00080   return as_pyint(app->num_molecules());
00081 }
00082 
00083 static const char mol_listall_doc[] =
00084 "List all valid molecule IDs\n\n"
00085 "Returns:\n"
00086 "    (list of int): Molids";
00087 static PyObject* py_mol_listall(PyObject *self, PyObject *args) {
00088   PyObject *newlist = NULL;
00089   int i;
00090 
00091   VMDApp *app;
00092   if (!(app = get_vmdapp()))
00093     return NULL;
00094 
00095   int num = app->num_molecules();
00096   if (!(newlist = PyList_New(num)))
00097     goto failure;
00098 
00099   for (i = 0; i < num; i++) {
00100     PyList_SET_ITEM(newlist, i, as_pyint(app->molecule_id(i)));
00101     if (PyErr_Occurred())
00102       goto failure;
00103   }
00104   return newlist;
00105 
00106 failure:
00107   Py_XDECREF(newlist);
00108   PyErr_SetString(PyExc_ValueError, "Problem listing molids");
00109   return NULL;
00110 }
00111 
00112 static const char mol_exists_doc[] =
00113 "Check if a molecule ID is valid\n\n"
00114 "Args:\n"
00115 "    molid (int): Molecule ID to query\n"
00116 "Returns:\n"
00117 "    (bool) True if molid is valid";
00118 static PyObject* py_mol_exists(PyObject *self, PyObject *args, PyObject *kwargs)
00119 {
00120   const char *kwlist[] = {"molid", NULL};
00121   int molid;
00122 
00123   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.exists",
00124                                    (char**) kwlist, &molid))
00125     return NULL;
00126 
00127   VMDApp *app;
00128   if (!(app = get_vmdapp()))
00129     return NULL;
00130 
00131   return as_pyint(app->molecule_valid_id(molid));
00132 }
00133 
00134 static const char mol_name_doc[] =
00135 "Get name of a given molecule\n\n"
00136 "Args:\n"
00137 "    molid (int): Molecule ID to query\n"
00138 "Returns:\n"
00139 "    (str): Molecule name";
00140 static PyObject* py_mol_name(PyObject *self, PyObject *args, PyObject *kwargs)
00141 {
00142   const char *kwlist[] = {"molid", NULL};
00143   int molid;
00144 
00145   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.name",
00146                                   (char**) kwlist, &molid))
00147     return NULL;
00148 
00149   VMDApp *app;
00150   if (!(app = get_vmdapp()))
00151     return NULL;
00152 
00153   if (!valid_molid(molid, app))
00154     return NULL;
00155 
00156   return as_pystring(app->molecule_name(molid));
00157 }
00158 
00159 static const char mol_numatoms_doc[] =
00160 "Get number of atoms in a given molecule\n\n"
00161 "Args:\n"
00162 "    molid (int): Molecule ID to query\n"
00163 "Returns:\n"
00164 "    (int): Number of atoms present in molecule";
00165 static PyObject* py_mol_numatoms(PyObject *self, PyObject *args,
00166                                  PyObject *kwargs)
00167 {
00168   const char *kwlist[] = {"molid", NULL};
00169   int molid;
00170 
00171   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.numatoms",
00172                                   (char**) kwlist, &molid))
00173     return NULL;
00174 
00175   VMDApp *app;
00176   if (!(app = get_vmdapp()))
00177     return NULL;
00178 
00179   if (!valid_molid(molid, app))
00180     return NULL;
00181 
00182   return as_pyint(app->molecule_numatoms(molid));
00183 }
00184 
00185 static const char mol_new_doc[] =
00186 "Create a new molecule, with optional number of 'empty' atoms\n\n"
00187 "Args:\n"
00188 "    name (str): Name of new molecule\n"
00189 "    natoms (int): Number of empty atoms in new molecule, optional.\n"
00190 "Returns:\n"
00191 "    (int): Molecule ID of created molecule";
00192 static PyObject* py_mol_new(PyObject *self, PyObject *args, PyObject *kwargs)
00193 {
00194   const char *kwlist[] = {"name", "natoms", NULL};
00195   int natoms = 0;
00196   char *name;
00197 
00198   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:molecule.new",
00199                                    (char**) kwlist, &name, &natoms))
00200     return NULL;
00201 
00202   VMDApp *app;
00203   if (!(app = get_vmdapp()))
00204     return NULL;
00205 
00206   if (natoms < 0) {
00207     PyErr_SetString(PyExc_ValueError, "natoms must be >= 0");
00208     return NULL;
00209   }
00210 
00211   int molid = app->molecule_new(name,natoms);
00212 
00213   if (molid < 0) {
00214     PyErr_Format(PyExc_ValueError, "Unable to create molecule name '%s'", name);
00215     return NULL;
00216   }
00217 
00218   return as_pyint(molid);
00219 }
00220 
00221 static const char mol_fromsel_doc[] =
00222 "Create a new molecule from multiple atomselections\n\n"
00223 "Args:\n"
00224 "    sellist (list): List of atomselections to be fused into a single molecule\n"
00225 "    name (str): Name of new molecule (optional)\n"
00226 "Returns:\n"
00227 "    (int): Molecule ID of created molecule";
00228 static PyObject* py_mol_fromsel(PyObject *self, PyObject *args, PyObject *kwargs)
00229 {
00230   const char *kwlist[] = {"", "name", NULL};
00231   PyObject *listObj;
00232   char *name = NULL;
00233 
00234   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|s:molecule.fromsel",
00235                                    (char**) kwlist, &PyList_Type, &listObj, &name))
00236     return NULL;
00237 
00238   VMDApp *app;
00239   if (!(app = get_vmdapp()))
00240     return NULL;
00241 
00242   AtomSel **asels = (AtomSel **) calloc(1, PyList_Size(listObj) * sizeof(AtomSel *));
00243   int s;
00244   int numsels = PyList_Size(listObj);
00245   for (s=0; s<numsels; s++) {
00246     asels[s] = atomsel_AsAtomSel(PyList_GetItem(listObj, s));
00247     if (!asels[s]) {
00248       PyErr_SetString(PyExc_ValueError, "mol fromsels: invalid atom selection list element");
00249       return NULL;
00250     }
00251   }
00252   int molid = app->molecule_from_selection_list(name, 0, numsels, asels);
00253   free(asels);
00254 
00255   if (molid < 0) {
00256     PyErr_Format(PyExc_ValueError, "Unable to create new molecule");
00257     return NULL;
00258   }
00259 
00260   return as_pyint(molid);
00261 }
00262 
00263 static const char mol_load_doc[] =
00264 "Load a molecule from a file. Can optionally read in coordinate files as\n"
00265 "well. Coordinate data does not have to be present in structure file\n"
00266 "Args:\n"
00267 "    struct_type (str): File type for structure data, or 'graphics' for\n"
00268 "        a blank molecule to add graphics to.\n"
00269 "    struct_file (str): Filename for structure data\n"
00270 "    coord_type (str): File type for coordinate data. Optional.\n"
00271 "    coord_file (str): Filename for coordinate data. Optional.\n"
00272 "Returns:\n"
00273 "    (int): Molecule ID of loaded molecule";
00274 static PyObject* py_mol_load(PyObject *self, PyObject *args, PyObject *kwargs)
00275 {
00276   const char *kwlist[] = {"struct_type", "struct_file", "coord_type",
00277                           "coord_file", NULL};
00278   char *coor = NULL, *cfname = NULL;
00279   char *structure, *sfname;
00280   FileSpec spec;
00281   int molid;
00282 
00283   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|zz:molecule.load",
00284                                    (char**) kwlist, &structure, &sfname,
00285                                    &coor, &cfname))
00286     return NULL;
00287 
00288   // if a coordinates file type was specified, a coordinate file must be given
00289   // as well, and vice versa.
00290   if (coor && !cfname) {
00291     PyErr_SetString(PyExc_ValueError, "No coordinate file specified");
00292     return NULL;
00293   }
00294   if (cfname && !coor) {
00295     PyErr_SetString(PyExc_ValueError, "No coordinate type specified");
00296     return NULL;
00297   }
00298 
00299   VMDApp *app;
00300   if (!(app = get_vmdapp()))
00301     return NULL;
00302 
00303   // Special-case graphics molecules to load as "blank" molecules
00304   if (!strcmp(structure, "graphics"))
00305     return as_pyint(app->molecule_new(sfname, 0));
00306 
00307   // Load all frames at once by default
00308   spec.waitfor = FileSpec::WAIT_ALL; // load all frames at once by default
00309   molid = app->molecule_load(-1, sfname, structure, &spec);
00310   if (molid < 0) {
00311     PyErr_Format(PyExc_RuntimeError, "Unable to load structure file '%s' "
00312                  "format '%s'", sfname, structure);
00313     return NULL;
00314   }
00315 
00316   // Load coordinate data if provided
00317   if (cfname && (app->molecule_load(molid, cfname, coor, &spec) < 0)) {
00318       PyErr_Format(PyExc_RuntimeError, "Unable to load coordinate file '%s' "
00319                    "format '%s'", cfname, coor);
00320   }
00321 
00322   return as_pyint(molid);
00323 }
00324 
00325 static const char mol_cancel_doc[] =
00326 "Cancel background loading of files for given molid\n\n"
00327 "Args:\n"
00328 "    molid (int): Molecule ID to cancel loading on";
00329 static PyObject* py_mol_cancel(PyObject *self, PyObject *args, PyObject *kwargs)
00330 {
00331   const char *kwlist[] = {"molid", NULL};
00332   int molid;
00333 
00334   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.cancel",
00335                                    (char**) kwlist, &molid))
00336     return NULL;
00337 
00338   VMDApp *app;
00339   if (!(app = get_vmdapp()))
00340     return NULL;
00341 
00342   if (!valid_molid(molid, app))
00343     return NULL;
00344 
00345   app->molecule_cancel_io(molid);
00346 
00347   Py_INCREF(Py_None);
00348   return Py_None;
00349 }
00350 
00351 static const char mol_delete_doc[] =
00352 "Delete a molecule\n\n"
00353 "Args:\n"
00354 "    molid (int): Molecule ID to delete";
00355 static PyObject* py_mol_delete(PyObject *self, PyObject *args, PyObject *kwargs)
00356 {
00357   const char *kwlist[] = {"molid", NULL};
00358   int molid;
00359 
00360   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.delete",
00361                                    (char**) kwlist,  &molid))
00362     return NULL;
00363 
00364   VMDApp *app;
00365   if (!(app = get_vmdapp()))
00366     return NULL;
00367 
00368   if (!valid_molid(molid, app))
00369     return NULL;
00370 
00371   app->molecule_delete(molid);
00372 
00373   Py_INCREF(Py_None);
00374   return Py_None;
00375 }
00376 
00377 static const char get_top_doc[] =
00378 "Get the ID of the top molecule\n\n"
00379 "Returns:\n"
00380 "    (int): Molecule ID of top molecule";
00381 static PyObject* py_get_top(PyObject *self, PyObject *args) {
00382   VMDApp *app;
00383   if (!(app = get_vmdapp()))
00384     return NULL;
00385 
00386   return as_pyint(app->molecule_top());
00387 }
00388 
00389 static const char set_top_doc[] =
00390 "Set the top molecule\n\n"
00391 "Args:\n"
00392 "    molid (int): Molecule ID of new top molecule";
00393 static PyObject* py_set_top(PyObject *self, PyObject *args, PyObject *kwargs) {
00394   const char *kwlist[] = {"molid", NULL};
00395   int molid;
00396 
00397   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.set_top",
00398                                    (char**) kwlist, &molid))
00399     return NULL;
00400 
00401   VMDApp *app;
00402   if (!(app = get_vmdapp()))
00403     return NULL;
00404 
00405   if (!valid_molid(molid, app))
00406     return NULL;
00407 
00408   app->molecule_make_top(molid);
00409 
00410   Py_INCREF(Py_None);
00411   return Py_None;
00412 }
00413 
00414 static const char mol_read_doc[] =
00415 "Read coordinate data into an existing molecule\n\n"
00416 "Args:\n"
00417 "    molid (int): Molecule ID to read data into\n"
00418 "    filetype (str): File type of coordinate data\n"
00419 "    filename (str): Path to coordinate data\n"
00420 "    first (int): First frame to read. Defaults to 0 (first frame)\n"
00421 "    last (int): Last frame to read, or -1 for the end. Defaults to -1\n"
00422 "    stride (int): Frame stride. Defaults to 1 (read all frames)\n"
00423 "    waitfor (int): Number of frames to load before returning. Defaults to 1,\n"
00424 "        then loads asyncronously in background. Set to -1 to load all frames\n"
00425 "    volsets (list of int): Indices of volumetric datasets to read in from\n"
00426 "        the file. Invalid indices will be ignored.";
00427 static PyObject* py_mol_read(PyObject *self, PyObject *args, PyObject *kwargs)
00428 {
00429   const char *kwlist[] = {"molid", "filetype", "filename", "first", "last",
00430                           "stride", "waitfor", "volsets", NULL};
00431   PyObject *volsets = NULL;
00432   char *filename, *type;
00433   int molid, rc;
00434   FileSpec spec;
00435 
00436   // Set default options
00437   spec.first = 0;
00438   spec.last = -1;
00439   spec.stride = 1;
00440   spec.waitfor = FileSpec::WAIT_BACK;
00441 
00442   // Handle legacy keywords beg, end, skip, but emit DeprecationWarning
00443   handle_legacy_keywords(kwargs);
00444 
00445   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iss|iiiiO!:molecule.read",
00446                                    (char**) kwlist, &molid, &type, &filename,
00447                                    &spec.first, &spec.last, &spec.stride,
00448                                    &spec.waitfor, &PyList_Type, &volsets))
00449     return NULL;
00450 
00451   VMDApp *app;
00452   if (!(app = get_vmdapp()))
00453     return NULL;
00454 
00455   // Read volumetric data if provided
00456   if (volsets) {
00457     spec.nvolsets = PyList_Size(volsets);
00458     spec.setids = new int[spec.nvolsets];
00459 
00460     for (int i=0; i<spec.nvolsets; i++) {
00461       spec.setids[i] = as_int(PyList_GET_ITEM(volsets, i));
00462       if (PyErr_Occurred())
00463         goto failure;
00464     }
00465 
00466   // If not volumetric data, have a default of {0} for setids so that it isn't
00467   // always necessary to specify the set id's. This should be ignored if the
00468   // file type can't read volumetric datasets
00469   } else {
00470     spec.nvolsets = 1;
00471     spec.setids = new int[1];
00472     spec.setids[0] = 0;
00473   }
00474 
00475   // Need to do more error checking here so we don't leak setids on error.
00476   rc = app->molecule_load(molid, filename, type, &spec);
00477   if (rc < 0) {
00478     PyErr_Format(PyExc_RuntimeError, "Unable to read filename '%s' "
00479                  "format '%s'", filename, type);
00480     goto failure;
00481   }
00482 
00483   return as_pyint(rc);
00484 
00485 failure:
00486   delete [] spec.setids;
00487   spec.setids = NULL;
00488   return NULL;
00489 }
00490 
00491 static const char mol_write_doc[] =
00492 "Write coordinate and topology data from a loaded molecule to a file\n\n"
00493 "Args:\n"
00494 "    molid (int): Molecule ID to read data into\n"
00495 "    filetype (str): File type of coordinate data\n"
00496 "    filename (str): Path to coordinate data\n"
00497 "    first (int): First frame to read. Defaults to 0 (first frame)\n"
00498 "    last (int): Last frame to read, or -1 for the end. Defaults to -1\n"
00499 "    stride (int): Frame stride. Defaults to 1 (write all frames)\n"
00500 "    waitfor (int): Number of frames to wait for before returning control. Defaults to -1 (wait for all frames)"
00501 "    selection (atomsel): Atom indices to write. Defaults to all atoms."
00502 "Returns:\n"
00503 "    (int): Number of frames written";
00504 static PyObject* py_mol_write(PyObject *self, PyObject *args, PyObject *kwargs)
00505 {
00506   const char *kwlist[] = {"molid", "filetype", "filename", "first", "last",
00507                           "stride", "waitfor", "selection", NULL};
00508   PyObject *selobj = NULL;
00509   char *filename, *type;
00510   int numframes, molid;
00511   int *on = NULL;
00512   FileSpec spec;
00513   Molecule *mol;
00514 
00515   // Set default options
00516   spec.first = 0;
00517   spec.last = -1;
00518   spec.stride = 1;
00519   spec.waitfor = FileSpec::WAIT_ALL;
00520 
00521   // Handle legacy keywords beg, end, skip, but emit DeprecationWarning
00522   handle_legacy_keywords(kwargs);
00523 
00524   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iss|iiiiO:molecule.write",
00525                                    (char**) kwlist, &molid, &type, &filename,
00526                                    &spec.first, &spec.last, &spec.stride, &spec.waitfor,
00527                                    &selobj))
00528     return NULL;
00529 
00530   VMDApp *app;
00531   if (!(app = get_vmdapp()))
00532     return NULL;
00533 
00534   if (!valid_molid(molid, app))
00535     return NULL;
00536 
00537   // Bounds check frames
00538   mol = app->moleculeList->mol_from_id(molid);
00539   if (spec.first >= mol->numframes() || spec.last >= mol->numframes()
00540    || spec.first < -1 || spec.last < -1) {
00541     PyErr_Format(PyExc_ValueError, "frames '%d-%d' out of bounds for molecule "
00542                 "'%d'", spec.first, spec.last, molid);
00543     return NULL;
00544   }
00545 
00546   // Get list of atom indices from optional atop selection object
00547   if (selobj && selobj != Py_None) {
00548     AtomSel *sel = atomsel_AsAtomSel( selobj );
00549     if (!sel || sel->molid() != molid) {
00550       PyErr_SetString(PyExc_ValueError, "Atomsel must be valid and must "
00551                       "reference same molecule as coordinates");
00552       return NULL;
00553     }
00554     on = sel->on;
00555   }
00556   spec.selection = on;
00557 
00558   numframes = app->molecule_savetrajectory(molid, filename, type, &spec);
00559   if (numframes < 0) {
00560     PyErr_Format(PyExc_ValueError, "Unable to save file '%s'", filename);
00561     return NULL;
00562   }
00563 
00564   return as_pyint(numframes);
00565 }
00566 
00567 static const char numframes_doc[] =
00568 "Get the number of loaded frames in a molecule\n\n"
00569 "Args:\n"
00570 "    molid (int): Molecule ID to query\n"
00571 "Returns:\n"
00572 "    (int): Number of loaded frames";
00573 static PyObject* py_numframes(PyObject *self, PyObject *args, PyObject *kwargs)
00574 {
00575   const char *kwlist[] = {"molid", NULL};
00576   int molid;
00577 
00578   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.numframes",
00579                                   (char**) kwlist, &molid))
00580     return NULL;
00581 
00582   VMDApp *app;
00583   if (!(app = get_vmdapp()))
00584     return NULL;
00585 
00586   if (!valid_molid(molid, app))
00587     return NULL;
00588 
00589   return as_pyint(app->molecule_numframes(molid));
00590 }
00591 
00592 static const char get_frame_doc[] =
00593 "Get the current frame\n\n"
00594 "Args:\n"
00595 "    molid (int): Molecule ID to query\n"
00596 "Returns:\n"
00597 "    (int): Current frame of molecule";
00598 static PyObject* py_get_frame(PyObject *self, PyObject *args, PyObject *kwargs)
00599 {
00600   const char *kwlist[] = {"molid", NULL};
00601   int molid;
00602 
00603   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_frame",
00604                                   (char**) kwlist,  &molid))
00605     return NULL;
00606 
00607   VMDApp *app;
00608   if (!(app = get_vmdapp()))
00609     return NULL;
00610 
00611   if (!valid_molid(molid, app))
00612     return NULL;
00613 
00614   return as_pyint(app->molecule_frame(molid));
00615 }
00616 
00617 static const char set_frame_doc[] =
00618 "Set the frame of a molecule\n\n"
00619 "Args:\n"
00620 "    molid (int): Molecule ID to set\n"
00621 "    frame (int): New frame for molecule";
00622 static PyObject* py_set_frame(PyObject *self, PyObject *args, PyObject *kwargs)
00623 {
00624   const char *kwlist[] = {"molid", "frame", NULL};
00625   int molid, frame;
00626 
00627   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:molecule.set_frame",
00628                                    (char**) kwlist, &molid, &frame))
00629     return NULL;
00630 
00631   VMDApp *app;
00632   if (!(app = get_vmdapp()))
00633     return NULL;
00634 
00635   if (!valid_molid(molid, app))
00636     return NULL;
00637 
00638   Molecule *mol = app->moleculeList->mol_from_id(molid);
00639 
00640   // Ensure frame is sane
00641   if (frame < 0 || frame >= mol->numframes()) {
00642     PyErr_Format(PyExc_ValueError, "frame '%d' out of bounds for molecule '%d'",
00643                  frame, molid);
00644     return NULL;
00645   }
00646 
00647   mol->override_current_frame(frame);
00648   mol->change_ts();
00649 
00650   Py_INCREF(Py_None);
00651   return Py_None;
00652 }
00653 
00654 static const char delframe_doc[] =
00655 "Delete a frame or frame(s) from a loaded molecule\n\n"
00656 "Args:\n"
00657 "    molid (int): Molecule ID to delete frames from\n"
00658 "    first (int): First frame to delete, inclusive. Defaults to 0.\n"
00659 "    last (int): Last frame to delete, inclusive. Defaults to -1 (last frame)\n"
00660 "    stride (int): Keep every Nth frame in range to delete. Defaults to 0.";
00661 static PyObject* py_delframe(PyObject *self, PyObject *args, PyObject *kwargs)
00662 {
00663   const char *kwlist[] = {"molid", "first", "last", "stride", NULL};
00664   int molid = 0, beg=0, end=-1, skip=0;
00665 
00666   // Handle legacy keywords beg, end, skip, but emit DeprecationWarning
00667   handle_legacy_keywords(kwargs);
00668 
00669   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:molecule.delframe",
00670                                    (char**) kwlist, &molid, &beg, &end, &skip))
00671     return NULL;
00672 
00673   // Handle legacy keywords beg, end, skip, but emit DeprecationWarning
00674   handle_legacy_keywords(kwargs);
00675 
00676   VMDApp *app;
00677   if (!(app = get_vmdapp()))
00678     return NULL;
00679 
00680   if (!valid_molid(molid, app))
00681     return NULL;
00682 
00683   if (!app->molecule_deleteframes(molid, beg, end, skip)) {
00684     PyErr_SetString(PyExc_ValueError, "Unable to delete frames");
00685     return NULL;
00686   }
00687 
00688   Py_INCREF(Py_None);
00689   return Py_None;
00690 }
00691 
00692 static const char dupframe_doc[] =
00693 "Duplicate a frame.\n\n"
00694 "Args:\n"
00695 "    molid (int): Molecule ID to duplicate frames on. If there are no loaded\n"
00696 "        frames in this molecule, a new frame with all zero coordinates will\n"
00697 "        be created.\n"
00698 "    frame (int): Frame to duplicate. Defaults to -1 (current frame)";
00699 static PyObject* py_dupframe(PyObject *self, PyObject *args, PyObject *kwargs)
00700 {
00701   const char *kwlist[] = {"molid", "frame", NULL};
00702   int frame = -1;
00703   int molid;
00704 
00705   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i:molecule.dupframe",
00706                                    (char**) kwlist, &molid, &frame))
00707     return NULL;
00708 
00709   VMDApp *app;
00710   if (!(app = get_vmdapp()))
00711     return NULL;
00712 
00713   if (!valid_molid(molid, app))
00714     return NULL;
00715 
00716   if (!app->molecule_dupframe(molid, frame)) {
00717     PyErr_Format(PyExc_ValueError, "Unable to duplicate frame '%d' in "
00718                  "molid '%d'", frame, molid);
00719     return NULL;
00720   }
00721 
00722   Py_INCREF(Py_None);
00723   return Py_None;
00724 }
00725 
00726 static const char mol_ssrecalc_doc[] =
00727 "Recalculate secondary structure for molecule\n\n"
00728 "Args:\n"
00729 "    molid (int): Molecule ID\n"
00730 "Raises:\n"
00731 "    RuntimeError: If structure could not be calculated, usually due to the\n"
00732 "        Stride program being unavailable";
00733 static PyObject *py_mol_ssrecalc(PyObject *self, PyObject *args,
00734                                  PyObject *kwargs) {
00735   const char *kwlist[] = {"molid", NULL};
00736   int molid, rc;
00737 
00738   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.ssrecalc",
00739                                    (char**) kwlist, &molid))
00740     return NULL;
00741 
00742   VMDApp *app;
00743   if (!(app = get_vmdapp()))
00744     return NULL;
00745 
00746   if (!valid_molid(molid, app))
00747     return NULL;
00748 
00749   // Release the GIL for this calculation
00750   Py_BEGIN_ALLOW_THREADS
00751   rc = app->molecule_ssrecalc(molid);
00752   Py_END_ALLOW_THREADS
00753 
00754   if (!rc) {
00755     PyErr_Format(PyExc_RuntimeError, "Secondary structure could not be "
00756                  "calculated for molid '%d'", molid);
00757     return NULL;
00758   }
00759 
00760   Py_INCREF(Py_None);
00761   return Py_None;
00762 }
00763 
00764 static const char mol_rename_doc[] =
00765 "Change the name of a molecule\n\n"
00766 "Args:\n"
00767 "    molid (int): Molecule ID to rename\n"
00768 "    name (str): New name for molecule";
00769 static PyObject* py_mol_rename(PyObject *self, PyObject *args, PyObject *kwargs)
00770 {
00771   const char *kwlist[] = {"molid", "name", NULL};
00772   char *newname;
00773   int molid;
00774 
00775   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "is:molecule.rename",
00776                                    (char**) kwlist, &molid, &newname))
00777     return NULL;
00778 
00779   VMDApp *app;
00780   if (!(app = get_vmdapp()))
00781     return NULL;
00782 
00783   if (!valid_molid(molid, app))
00784     return NULL;
00785 
00786   if (!app->molecule_rename(molid, newname)) {
00787     PyErr_Format(PyExc_ValueError, "Unable to rename molecule '%d'", molid);
00788     return NULL;
00789   }
00790 
00791   Py_INCREF(Py_None);
00792   return Py_None;
00793 }
00794 
00795 static const char add_volumetric_doc[] =
00796 "Add a new volumetric dataset to a molecule\n\n"
00797 "Args:\n"
00798 "    molid (int): Molecule ID to add dataset to\n"
00799 "    name (str): Dataset name\n"
00800 "    size (3-tuple of int): Size of grid data in X, Y, and Z dimensions\n"
00801 "    data (list of float): Grid data, of length xsize * ysize * zsize\n"
00802 "    origin (3-tuple of float): (x,y,z) coordinate of grid origin, at lower left\n"
00803 "        rear corner of grid. Defaults to (0,0,0)\n"
00804 "    xaxis (3-tuple of float): (x,y,z) vector for X axis. Defaults to (1,0,0)\n"
00805 "    yaxis (3-tuple of float): (x,y,z) vector for Y axis. Defaults to (0,1,0)\n"
00806 "    zaxis (3-tuple of float): (x,y,z) vector for Z axis. Defaults to (0,0,1)";
00807 static PyObject *py_mol_add_volumetric(PyObject *self, PyObject *args,
00808                                        PyObject *kwargs) {
00809   const char *kwlist[] = {"molid", "name", "size", "data",
00810                           "origin", "xaxis", "yaxis", "zaxis", NULL};
00811   float forigin[3] = {0.f, 0.f, 0.f};
00812   float fxaxis[3] = {1.f, 0.f, 0.f};
00813   float fyaxis[3] = {0.f, 1.f, 0.f};
00814   float fzaxis[3] = {0.f, 0.f, 1.f};
00815   PyObject *seqdata = NULL;
00816   float *fdata = NULL;
00817   int totalsize, i;
00818   PyObject *data;
00819   int molid = -1;
00820   int size[3];
00821   char *name;
00822 
00823   // Handle deprecated xsize, ysize, zsize arguments
00824   if (kwargs && PyDict_GetItemString(kwargs, "xsize")
00825       && PyDict_GetItemString(kwargs, "ysize")
00826       && PyDict_GetItemString(kwargs, "zsize")) {
00827 
00828     data = Py_BuildValue("(OOO)", PyDict_GetItemString(kwargs, "xsize"),
00829                          PyDict_GetItemString(kwargs, "ysize"),
00830                          PyDict_GetItemString(kwargs, "zsize"));
00831 
00832     PyDict_DelItemString(kwargs, "xsize");
00833     PyDict_DelItemString(kwargs, "ysize");
00834     PyDict_DelItemString(kwargs, "zsize");
00835 
00836     PyDict_SetItemString(kwargs, "size", data);
00837     Py_DECREF(data);
00838 
00839     PyErr_Warn(PyExc_DeprecationWarning, "xsize, ysize, zsize keywords are "
00840                "deprecated, pass size as a tuple instead");
00841   }
00842 
00843   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
00844                                    "is(iii)O|O&O&O&O&:molecule.add_volumetric",
00845                                    (char**) kwlist, &molid, &name, &size[0],
00846                                    &size[1], &size[2], &data,
00847                                    &py_array_from_obj, &forigin,
00848                                    &py_array_from_obj, &fxaxis,
00849                                    &py_array_from_obj, &fyaxis,
00850                                    &py_array_from_obj, &fzaxis))
00851     return NULL;
00852 
00853   VMDApp *app;
00854   if (!(app = get_vmdapp()))
00855     return NULL;
00856 
00857   if (!valid_molid(molid, app))
00858     return NULL;
00859 
00860   // Validate size parameters
00861   if (size[0] < 1 || size[1] < 1 || size[2] < 1) {
00862     PyErr_SetString(PyExc_ValueError, "Volumetric sizes must be >= 1");
00863     goto failure;
00864   }
00865 
00866   // Handle either list or tuple for data
00867   if (!(seqdata = PySequence_Fast(data, "data must be a list or tuple")))
00868     goto failure;
00869 
00870   totalsize = size[0] * size[1] * size[2];
00871   if (PyList_Size(data) != totalsize) {
00872     PyErr_Format(PyExc_ValueError, "size of data list '%ld' does not match "
00873                  "expected grid size %d x %d x %d",
00874                  PySequence_Fast_GET_SIZE(seqdata),
00875                  size[0], size[1], size[2]);
00876     goto failure;
00877   }
00878 
00879   // allocate float array here; pass it to molecule
00880   fdata = new float[totalsize];
00881   for (i = 0; i < totalsize; i++) {
00882     PyObject *elem = PySequence_Fast_GET_ITEM(seqdata, i);
00883 
00884     if (!PyFloat_Check(elem)) {
00885       PyErr_SetString(PyExc_TypeError, "Volumetric data must be floats");
00886       goto failure;
00887     }
00888 
00889     float tmp = PyFloat_AsDouble(elem);
00890 
00891     if (PyErr_Occurred())
00892       goto failure;
00893 
00894     fdata[i] = tmp;
00895   }
00896 
00897   if (!app->molecule_add_volumetric(molid, name, forigin, fxaxis, fyaxis,
00898        fzaxis, size[0], size[1], size[2], fdata)) {
00899     PyErr_Format(PyExc_ValueError, "Unable to add volumetric data to molid %d",
00900                  molid);
00901     goto failure;
00902   }
00903 
00904   Py_DECREF(seqdata);
00905   Py_INCREF(Py_None);
00906   return Py_None;
00907 
00908 failure:
00909   Py_XDECREF(seqdata);
00910   if (fdata)
00911     delete [] fdata;
00912   return NULL;
00913 }
00914 
00915 static const char del_volumetric_doc[] =
00916 "Delete a volumetric dataset from a molecule\n\n"
00917 "Args:\n"
00918 "    molid (int): Molecule ID to remove dataset from\n"
00919 "    dataindex (int): Volumetric dataset index to delete";
00920 static PyObject* py_mol_del_volumetric(PyObject *self, PyObject *args,
00921                                        PyObject *kwargs)
00922 {
00923   const char *kwlist[] = {"molid", "dataindex", NULL};
00924   int molid, index;
00925 
00926   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:molecule.delete_volumetric",
00927                                   (char**) kwlist,  &molid, &index))
00928     return NULL;
00929 
00930   VMDApp *app;
00931   if (!(app = get_vmdapp()))
00932     return NULL;
00933 
00934   if (!valid_molid(molid, app))
00935     return NULL;
00936 
00937   Molecule *mol = app->moleculeList->mol_from_id(molid);
00938   if (index < 0 || index >= mol->num_volume_data()) {
00939     PyErr_Format(PyExc_ValueError, "Invalid volumetric index '%d'", index);
00940     return NULL;
00941   }
00942 
00943   mol->remove_volume_data(index);
00944   Py_INCREF(Py_None);
00945   return Py_None;
00946 }
00947 
00948 // Deprecated name for del_volumetric
00949 static PyObject *py_mol_drm_volumetric(PyObject *self, PyObject *args,
00950                                        PyObject *kwargs) {
00951   PyErr_Warn(PyExc_DeprecationWarning, "the 'remove_volumetric' method has "
00952              "been renamed to 'delete_volumetric'");
00953   return py_mol_del_volumetric(self, args, kwargs);
00954 }
00955 
00956 static const char get_volumetric_doc[] =
00957 "Obtain a volumetric dataset loaded into a molecule\n\n"
00958 "Args:\n"
00959 "    molid (int): Molecule ID to query\n"
00960 "    dataindex (int): Volumetric dataset index to obtain\n"
00961 "Returns:\n"
00962 "    (4-list): Dataset, consisting of 4 lists:\n"
00963 "        1.) A 1-D list of the values at each point\n"
00964 "        2.) 3-tuple of int describing the x, y, z lengths.\n"
00965 "        3.) 3-tuple of float describing the position of the origin.\n"
00966 "        4.) 9-tuple of float describing the deltas for the x, y, and z axes)."
00967 "\n\n"
00968 "Example usage for export to numpy:\n"
00969 "    >>> data, shape, origin, delta = molecule.get_volumetric(0,0)\n"
00970 "    >>> data = np.array(data)\n"
00971 "    >>> shape = np.array(shape)\n"
00972 "    >>> data = data.reshape(shape, order='F')\n"
00973 "    >>> delta = np.array(delta).reshape(3,3)\n"
00974 "    >>> delta /= shape-1";
00975 static PyObject* py_mol_get_volumetric(PyObject *self, PyObject *args,
00976                                        PyObject *kwargs)
00977 {
00978   const char *kwlist[] = {"molid", "dataindex", NULL};
00979   PyObject *result = NULL, *deltas = NULL, *origin = NULL;
00980   PyObject *size = NULL, *data = NULL;
00981   const VolumetricData *synthvol;
00982   int molid, index, dsize, i;
00983 
00984   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:molecule.get_volumetric",
00985                                    (char**) kwlist, &molid, &index))
00986     return NULL;
00987 
00988   VMDApp *app;
00989   if (!(app = get_vmdapp()))
00990     return NULL;
00991 
00992   if (!valid_molid(molid, app))
00993     return NULL;
00994 
00995   Molecule *mol = app->moleculeList->mol_from_id(molid);
00996   if (index < 0 || index >= mol->num_volume_data()) {
00997     PyErr_Format(PyExc_ValueError, "Invalid volumetric index '%d'", index);
00998     return NULL;
00999   }
01000 
01001   // Calculate size for data array
01002   synthvol = mol->get_volume_data(index);
01003   dsize = synthvol->xsize * synthvol->ysize * synthvol->zsize;
01004 
01005   // Create data structures to be returned
01006   result = PyList_New(4);
01007   deltas = PyTuple_New(9);
01008   origin = PyTuple_New(3);
01009   size = PyTuple_New(3);
01010   data = PyList_New(dsize);
01011 
01012   if (!result || !deltas || !origin || !size || !data) {
01013     PyErr_Format(PyExc_MemoryError, "Cannot allocate volumetric data arrays "
01014                  "for molid %d volindex %d", molid, index);
01015     goto failure;
01016   }
01017 
01018   // Build data array list
01019   for (i = 0; i < dsize; i++) {
01020     if (PyList_SetItem(data, i, PyFloat_FromDouble(synthvol->data[i]))) {
01021       PyErr_Format(PyExc_RuntimeError, "Cannot build data array for molid %d "
01022                    "volindex %d", molid, index);
01023       goto failure;
01024     }
01025   }
01026 
01027   // Build box size list
01028   if (PyTuple_SetItem(size, 0, as_pyint(synthvol->xsize))
01029       || PyTuple_SetItem(size, 1, as_pyint(synthvol->ysize))
01030       || PyTuple_SetItem(size, 2, as_pyint(synthvol->zsize))) {
01031     PyErr_Format(PyExc_RuntimeError, "Cannot build box size list for molid %d "
01032                  "volindex %d", molid, index);
01033     goto failure;
01034   }
01035 
01036   // Build axis vector list
01037   for (i = 0; i < 3; i++) {
01038     if (PyTuple_SetItem(deltas, i, PyFloat_FromDouble(synthvol->xaxis[i]))
01039      || PyTuple_SetItem(deltas, 3+i, PyFloat_FromDouble(synthvol->yaxis[i]))
01040      || PyTuple_SetItem(deltas, 6+i, PyFloat_FromDouble(synthvol->zaxis[i]))
01041      || PyTuple_SetItem(origin, i, PyFloat_FromDouble(synthvol->origin[i]))) {
01042       PyErr_Format(PyExc_RuntimeError, "Cannot build axis vector list for molid"
01043                    " %d volindex %d", molid, index);
01044       goto failure;
01045     }
01046   }
01047 
01048   // Finally, build list of lists that's returned
01049   PyList_SET_ITEM(result, 0, data);
01050   PyList_SET_ITEM(result, 1, size);
01051   PyList_SET_ITEM(result, 2, origin);
01052   PyList_SET_ITEM(result, 3, deltas);
01053 
01054   if (PyErr_Occurred()) {
01055     PyErr_Format(PyExc_RuntimeError, "Problem building volumetric information "
01056                  "list for molid %d volindex %d", molid, index);
01057     goto failure;
01058   }
01059 
01060   return result;
01061 
01062 failure:
01063   Py_XDECREF(data);
01064   Py_XDECREF(deltas);
01065   Py_XDECREF(origin);
01066   Py_XDECREF(size);
01067   Py_XDECREF(result);
01068   return NULL;
01069 }
01070 
01071 static const char num_volumetric_doc[] =
01072 "Get the number of volumetric datasets loaded into a molecule\n\n"
01073 "Args:\n"
01074 "    molid (int): Molecule ID to query\n"
01075 "Returns:\n"
01076 "    (int): Number of volumetric datasets loaded";
01077 static PyObject* py_mol_num_volumetric(PyObject *self, PyObject *args,
01078                                        PyObject *kwargs)
01079 {
01080   const char *kwlist[] = {"molid", NULL};
01081   int molid;
01082 
01083   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.num_volumetric",
01084                                    (char**) kwlist, &molid))
01085     return NULL;
01086 
01087   VMDApp *app;
01088   if (!(app = get_vmdapp()))
01089     return NULL;
01090 
01091   if (!valid_molid(molid, app))
01092     return NULL;
01093 
01094   Molecule *mol = app->moleculeList->mol_from_id(molid);
01095   return as_pyint(mol->num_volume_data());
01096 }
01097 
01098 
01099 static const char filenames_doc[] =
01100 "Get list of all files loaded into a molecule\n\n"
01101 "Args:\n"
01102 "    molid (int): Molecule ID to query\n"
01103 "Returns:\n"
01104 "    (list of str): Paths to files loaded in molecule";
01105 static PyObject* py_get_filenames(PyObject *self, PyObject *args,
01106                                   PyObject *kwargs)
01107 {
01108   const char *kwlist[] = {"molid", NULL};
01109   PyObject *result;
01110   int molid;
01111 
01112   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_filenames",
01113                                    (char**) kwlist, &molid))
01114     return NULL;
01115 
01116   VMDApp *app;
01117   if (!(app = get_vmdapp()))
01118     return NULL;
01119 
01120   if (!valid_molid(molid, app))
01121     return NULL;
01122 
01123   Molecule *mol = app->moleculeList->mol_from_id(molid);
01124 
01125   result = PyList_New(mol->num_files());
01126   for (int i=0; i<mol->num_files(); i++) {
01127     PyList_SET_ITEM(result, i, as_pystring(mol->get_file(i)));
01128 
01129     if (PyErr_Occurred()) {
01130       PyErr_Format(PyExc_RuntimeError, "Problem listing loaded files in molid "
01131                    "'%d'", molid);
01132       Py_DECREF(result);
01133       return NULL;
01134     }
01135   }
01136   return result;
01137 }
01138 
01139 static const char filetypes_doc[] =
01140 "Get file types loaded into a molecule\n\n"
01141 "Args:\n"
01142 "    molid (int): Molecule ID to query\n"
01143 "Returns:\n"
01144 "    (list of str): File types loaded into molecule";
01145 static PyObject* py_get_filetypes(PyObject *self, PyObject *args,
01146                                   PyObject *kwargs)
01147 {
01148   const char *kwlist[] = {"molid", NULL};
01149   PyObject *result;
01150   int molid;
01151 
01152   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_filetypes",
01153                                    (char**) kwlist, &molid))
01154     return NULL;
01155 
01156   VMDApp *app;
01157   if (!(app = get_vmdapp()))
01158     return NULL;
01159 
01160   if (!valid_molid(molid, app))
01161     return NULL;
01162 
01163   Molecule *mol = app->moleculeList->mol_from_id(molid);
01164   result = PyList_New(mol->num_files());
01165 
01166   for (int i=0; i<mol->num_files(); i++) {
01167     PyList_SET_ITEM(result, i, as_pystring(mol->get_type(i)));
01168 
01169     // Delete built list on error
01170     if (PyErr_Occurred()) {
01171       PyErr_Format(PyExc_RuntimeError, "Problem listing filetypes in molid "
01172                    "'%d'", molid);
01173       Py_DECREF(result);
01174       return NULL;
01175     }
01176 
01177   }
01178   return result;
01179 }
01180 
01181 static const char databases_doc[] =
01182 "Get databases associated with files loaded into a molecule\n\n"
01183 "Args:\n"
01184 "    molid (int): Molecule ID to query\n"
01185 "Returns:\n"
01186 "    (list of str): Databases loaded into molecule. If no database is\n"
01187 "        associated with a given file loaded into the molecule, an empty\n"
01188 "        list will be returned";
01189 static PyObject* py_get_databases(PyObject *self, PyObject *args,
01190                                   PyObject *kwargs)
01191 {
01192   const char *kwlist[] = {"molid", NULL};
01193   PyObject *result;
01194   int molid;
01195 
01196   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_databases",
01197                                    (char**) kwlist, &molid))
01198     return NULL;
01199 
01200   VMDApp *app;
01201   if (!(app = get_vmdapp()))
01202     return NULL;
01203 
01204   if (!valid_molid(molid, app))
01205     return NULL;
01206 
01207   Molecule *mol = app->moleculeList->mol_from_id(molid);
01208   result = PyList_New(mol->num_files());
01209 
01210   for (int i=0; i<mol->num_files(); i++) {
01211     PyList_SET_ITEM(result, i, as_pystring(mol->get_database(i)));
01212 
01213     // Delete built list on error
01214     if (PyErr_Occurred()) {
01215       PyErr_Format(PyExc_RuntimeError, "Problem listing databases in molid "
01216                    "'%d'", molid);
01217       Py_DECREF(result);
01218       return NULL;
01219     }
01220   }
01221   return result;
01222 }
01223 
01224 static const char accessions_doc[] =
01225 "Get database accession codes associated with files loaded into a molecule\n\n"
01226 "Args:\n"
01227 "    molid (int): Molecule ID to query\n"
01228 "Returns:\n"
01229 "    (list of str): Accession codes loaded into molecule. If no accession is\n"
01230 "        associated with a given file loaded into the molecule, an empty\n"
01231 "        list will be returned.";
01232 static PyObject* py_get_accessions(PyObject *self, PyObject *args,
01233                                    PyObject *kwargs)
01234 {
01235   const char *kwlist[] = {"molid", NULL};
01236   PyObject *result;
01237   int molid;
01238 
01239   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_accessions",
01240                                    (char**) kwlist, &molid))
01241     return NULL;
01242 
01243   VMDApp *app;
01244   if (!(app = get_vmdapp()))
01245     return NULL;
01246 
01247   if (!valid_molid(molid, app))
01248     return NULL;
01249 
01250   Molecule *mol = app->moleculeList->mol_from_id(molid);
01251   result = PyList_New(mol->num_files());
01252 
01253   for (int i=0; i<mol->num_files(); i++) {
01254     PyList_SET_ITEM(result, i, as_pystring(mol->get_accession(i)));
01255 
01256     // Delete built list on error
01257     if (PyErr_Occurred()) {
01258       PyErr_Format(PyExc_RuntimeError, "Problem listing databases in molid "
01259                    "'%d'", molid);
01260       Py_DECREF(result);
01261       return NULL;
01262     }
01263   }
01264   return result;
01265 }
01266 
01267 static const char remarks_doc[] =
01268 "Get remarks associated with files loaded into a molecule\n\n"
01269 "Args:\n"
01270 "    molid (int): Molecule ID to query\n"
01271 "Returns:\n"
01272 "    (list of str): Remarks present in the molecule, one string per loaded\n"
01273 "        file with remark information. Multiple remarks in the same file will\n"
01274 "        be separated by newline (\\n) characters. If no remarks are\n"
01275 "        associated with a given file loaded into the molecule, an empty\n"
01276 "        string will be present in the list. If no remarks are associated\n"
01277 "        with the molecule, an empty list will be returned.";
01278 static PyObject* py_get_remarks(PyObject *self, PyObject *args,
01279                                 PyObject *kwargs)
01280 {
01281   const char *kwlist[] = {"molid", NULL};
01282   PyObject *result;
01283   int molid;
01284 
01285   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:molecule.get_remarks",
01286                                    (char**) kwlist, &molid))
01287     return NULL;
01288 
01289   VMDApp *app;
01290   if (!(app = get_vmdapp()))
01291     return NULL;
01292 
01293   if (!valid_molid(molid, app))
01294     return NULL;
01295 
01296   Molecule *mol = app->moleculeList->mol_from_id(molid);
01297   result = PyList_New(mol->num_files());
01298 
01299   for (int i=0; i<mol->num_files(); i++) {
01300     PyList_SET_ITEM(result, i, as_pystring(mol->get_remarks(i)));
01301 
01302     // Delete built list on error
01303     if (PyErr_Occurred()) {
01304       PyErr_Format(PyExc_RuntimeError, "Problem listing remarks in molid '%d'",
01305                    molid);
01306       Py_DECREF(result);
01307       return NULL;
01308     }
01309   }
01310   return result;
01311 }
01312 
01313 
01314 static const char get_periodic_doc[] =
01315 "Get the periodic cell layout\n\n"
01316 "Args:\n"
01317 "    molid (int): Molecule ID to query. Defaults to -1 (top molecule)\n"
01318 "    frame (int): Frame to get box information from. Defaults to -1 (current)\n"
01319 "Returns:\n"
01320 "    (dict str->float): Periodic cell layout with values for keys 'a', 'b',\n"
01321 "        and 'c' representing the lengths of the unit cell along the first,\n"
01322 "        second, and third unit cell vectors, respectively. Values for keys\n"
01323 "        'alpha', 'beta', and 'gamma' give the angle between sides B and C,\n"
01324 "        A and C, and A and B, respectively.";
01325 static PyObject* py_get_periodic(PyObject *self, PyObject *args,
01326                                  PyObject *kwargs)
01327 {
01328   const char *kwlist[] = {"molid", "frame", NULL};
01329   int molid=-1, frame=-1;
01330   PyObject *dict;
01331 
01332   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:molecule.get_periodic",
01333                                    (char**) kwlist, &molid, &frame))
01334     return NULL;
01335 
01336   VMDApp *app;
01337   if (!(app = get_vmdapp()))
01338     return NULL;
01339 
01340   if (molid == -1)
01341     molid = app->molecule_top();
01342   if (!valid_molid(molid, app))
01343     return NULL;
01344 
01345   // Get frame number
01346   Timestep *ts = parse_timestep(app, molid, frame);
01347   if (!ts)
01348     return NULL;
01349 
01350   dict = PyDict_New();
01351   PyDict_SetItemString(dict, "a", PyFloat_FromDouble(ts->a_length));
01352   PyDict_SetItemString(dict, "b", PyFloat_FromDouble(ts->b_length));
01353   PyDict_SetItemString(dict, "c", PyFloat_FromDouble(ts->c_length));
01354   PyDict_SetItemString(dict, "alpha", PyFloat_FromDouble(ts->alpha));
01355   PyDict_SetItemString(dict, "beta", PyFloat_FromDouble(ts->beta));
01356   PyDict_SetItemString(dict, "gamma", PyFloat_FromDouble(ts->gamma));
01357 
01358   // Clean up dictionary if something went wrong
01359   if (PyErr_Occurred()) {
01360     PyErr_SetString(PyExc_RuntimeError, "Problem getting box info");
01361     Py_DECREF(dict);
01362     return NULL;
01363   }
01364 
01365   return dict;
01366 }
01367 
01368 static const char set_periodic_doc[] =
01369 "Set the periodic cell layout for a particular frame. Any number of box\n"
01370 "attributes may be changed at a time\n\n"
01371 "Args:\n"
01372 "    molid (int): Molecule ID. Defaults to -1 (top molecule)\n"
01373 "    frame (int): Frame to change box info for. Defaults to -1 (current)\n"
01374 "    a (float): Length of unit cell along first cell vector. Optional\n"
01375 "    b (float): Length of unit cell along second cell vector. Optional\n"
01376 "    c (float): Length of unit cell along third cell vector. Optional\n"
01377 "    alpha (float): Angle between cell sides B and C. Optional\n"
01378 "    beta (float): Angle between cell sides A and C. Optional\n"
01379 "    gamma (float): Angle between cell sides A and B. Optional";
01380 static PyObject *py_set_periodic(PyObject *self, PyObject *args,
01381                                  PyObject *kwargs)
01382 {
01383   const char *kwlist[] = {"molid", "frame", "a", "b", "c", "alpha", "beta",
01384                           "gamma", NULL};
01385   float a=-1, b=-1, c=-1, alpha=-1, beta=-1, gamma=-1;
01386   int molid = -1, frame = -1;
01387 
01388   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
01389                                    "|iiffffff:molecule.set_periodic",
01390                                    (char**)  kwlist, &molid, &frame, &a, &b,
01391                                    &c, &alpha, &beta, &gamma))
01392     return NULL;
01393 
01394   VMDApp *app;
01395   if (!(app = get_vmdapp()))
01396     return NULL;
01397 
01398   if (molid == -1)
01399     molid = app->molecule_top();
01400   if (!valid_molid(molid, app))
01401     return NULL;
01402 
01403   Timestep *ts = parse_timestep(app, molid, frame);
01404   if (!ts)
01405     return NULL;
01406 
01407   if (a >= 0)
01408     ts->a_length = a;
01409   if (b >= 0)
01410     ts->b_length = b;
01411   if (c >= 0)
01412     ts->c_length = c;
01413   if (alpha > 0)
01414     ts->alpha = alpha;
01415   if (beta > 0)
01416     ts->beta = beta;
01417   if (gamma > 0)
01418     ts->gamma = gamma;
01419 
01420   Py_INCREF(Py_None);
01421   return Py_None;
01422 }
01423 
01424 static const char get_visible_doc[] =
01425 "Get if a molecule is visible\n\n"
01426 "Args:\n"
01427 "    molid (int): Molecule ID to query. Defaults to -1 (top molecule)\n"
01428 "Returns:\n"
01429 "    (bool): If molecule is visible";
01430 static PyObject* py_get_visible(PyObject *self, PyObject *args,PyObject *kwargs)
01431 {
01432   const char *kwlist[] = {"molid", NULL};
01433   int molid = -1;
01434 
01435   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:molecule.get_visible",
01436                                    (char**) kwlist, &molid))
01437     return NULL;
01438 
01439   VMDApp *app;
01440   if (!(app = get_vmdapp()))
01441     return NULL;
01442 
01443   if (molid<0)
01444     molid = app->molecule_top();
01445   if (!valid_molid(molid, app))
01446     return NULL;
01447 
01448   return PyBool_FromLong(app->molecule_is_displayed(molid));
01449 }
01450 
01451 static const char set_visible_doc[] =
01452 "Set the visiblity of a molecule\n\n"
01453 "Args:\n"
01454 "    molid (int): Molecule ID\n"
01455 "    visible (bool): If molecule should be visible";
01456 static PyObject* py_set_visible(PyObject *self, PyObject *args,
01457                                 PyObject *kwargs)
01458 {
01459   const char *kwlist[] = {"molid", "visible", NULL};
01460   PyObject *value;
01461   int molid = -1;
01462   int visible;
01463 
01464   // Handle legacy "state" keyword -> visible
01465   if (kwargs && (value = PyDict_GetItemString(kwargs, "state"))) {
01466     PyDict_SetItemString(kwargs, "visible", value);
01467     PyDict_DelItemString(kwargs, "state");
01468     PyErr_Warn(PyExc_DeprecationWarning, "'state' keywords is 'visible' now");
01469   }
01470 
01471   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O&:molecule.set_visible",
01472                                    (char**) kwlist, &molid, convert_bool,
01473                                    &visible))
01474     return NULL;
01475 
01476   VMDApp *app;
01477   if (!(app = get_vmdapp()))
01478     return NULL;
01479 
01480   if (!valid_molid(molid, app))
01481     return NULL;
01482 
01483   app->molecule_display(molid, visible);
01484   Py_INCREF(Py_None);
01485   return Py_None;
01486 }
01487 
01488 static const char time_doc[] =
01489 "Get the physical time value for a frame, if set\n\n"
01490 "Args:\n"
01491 "    molid (int): Molecule ID to query\n"
01492 "    frame (int): Frame to query. Defaults to -1 (current)\n"
01493 "Returns:\n"
01494 "    (float): Physical time value for frame, or 0.0f if unset";
01495 static PyObject* py_get_physical_time(PyObject *self, PyObject *args,
01496                                       PyObject *kwargs)
01497 {
01498   const char *kwlist[] = {"molid", "frame", NULL};
01499   int molid = -1, frame = -1;
01500 
01501   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
01502                                    "i|i:molecule.get_physical_time",
01503                                    (char**) kwlist, &molid, &frame))
01504     return NULL;
01505 
01506   VMDApp *app;
01507   if (!(app = get_vmdapp()))
01508     return NULL;
01509 
01510   if (!valid_molid(molid, app))
01511     return NULL;
01512 
01513   Timestep *ts = parse_timestep(app, molid, frame);
01514   if (!ts)
01515     return NULL;
01516 
01517   return PyFloat_FromDouble(ts->physical_time);
01518 }
01519 
01520 static const char settime_doc[] =
01521 "Set the physical time value for a frame\n\n"
01522 "Args:\n"
01523 "    molid (int): Molecule ID to set time for.\n"
01524 "    time (float): Time value\n"
01525 "    frame (int): Frame to set time for. Defaults to -1 (current)\n";
01526 static PyObject* py_set_physical_time(PyObject *self, PyObject *args,
01527                                       PyObject *kwargs)
01528 {
01529   const char *kwlist[] = {"molid", "time", "frame", NULL};
01530   int molid = -1, frame = -1;
01531   double value;
01532 
01533   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
01534                                    "id|i:molecule.set_physical_time",
01535                                    (char**)  kwlist, &molid, &value, &frame))
01536     return NULL;
01537 
01538   VMDApp *app;
01539   if (!(app = get_vmdapp()))
01540     return NULL;
01541 
01542   if (!valid_molid(molid, app))
01543     return NULL;
01544 
01545   Timestep *ts = parse_timestep(app, molid, frame);
01546   if (!ts)
01547     return NULL;
01548 
01549   ts->physical_time = value;
01550 
01551   Py_INCREF(Py_None);
01552   return Py_None;
01553 }
01554 
01555 static PyMethodDef methods[] = {
01556   {"num", (PyCFunction)py_mol_num, METH_NOARGS, mol_num_doc },
01557   {"listall", (PyCFunction)py_mol_listall, METH_VARARGS | METH_KEYWORDS ,mol_listall_doc},
01558   {"exists", (PyCFunction)py_mol_exists, METH_VARARGS | METH_KEYWORDS, mol_exists_doc},
01559   {"name", (PyCFunction)py_mol_name, METH_VARARGS | METH_KEYWORDS, mol_name_doc},
01560   {"numatoms", (PyCFunction)py_mol_numatoms, METH_VARARGS | METH_KEYWORDS, mol_numatoms_doc},
01561   {"new", (PyCFunction)py_mol_new, METH_VARARGS | METH_KEYWORDS, mol_new_doc},
01562   {"fromsel", (PyCFunction)py_mol_fromsel, METH_VARARGS | METH_KEYWORDS, mol_fromsel_doc},
01563   {"load", (PyCFunction)py_mol_load, METH_VARARGS | METH_KEYWORDS, mol_load_doc},
01564   {"cancel", (PyCFunction)py_mol_cancel, METH_VARARGS | METH_KEYWORDS, mol_cancel_doc},
01565   {"delete", (PyCFunction)py_mol_delete, METH_VARARGS | METH_KEYWORDS, mol_delete_doc},
01566   {"get_top", (PyCFunction)py_get_top, METH_NOARGS, get_top_doc},
01567   {"set_top", (PyCFunction)py_set_top, METH_VARARGS | METH_KEYWORDS, set_top_doc},
01568   {"read", (PyCFunction)py_mol_read, METH_VARARGS | METH_KEYWORDS, mol_read_doc},
01569   {"write", (PyCFunction)py_mol_write, METH_VARARGS | METH_KEYWORDS, mol_write_doc},
01570   {"numframes", (PyCFunction)py_numframes, METH_VARARGS | METH_KEYWORDS, numframes_doc},
01571   {"get_frame", (PyCFunction)py_get_frame, METH_VARARGS | METH_KEYWORDS, get_frame_doc},
01572   {"set_frame", (PyCFunction)py_set_frame, METH_VARARGS | METH_KEYWORDS, set_frame_doc},
01573   {"delframe", (PyCFunction)py_delframe, METH_VARARGS | METH_KEYWORDS, delframe_doc},
01574   {"dupframe", (PyCFunction)py_dupframe, METH_VARARGS | METH_KEYWORDS, dupframe_doc},
01575   {"ssrecalc", (PyCFunction)py_mol_ssrecalc, METH_VARARGS | METH_KEYWORDS, mol_ssrecalc_doc},
01576   {"rename", (PyCFunction)py_mol_rename, METH_VARARGS | METH_KEYWORDS, mol_rename_doc},
01577   {"add_volumetric", (PyCFunction)py_mol_add_volumetric,
01578                       METH_VARARGS | METH_KEYWORDS, add_volumetric_doc},
01579   {"delete_volumetric", (PyCFunction)py_mol_del_volumetric,
01580                         METH_VARARGS | METH_KEYWORDS, del_volumetric_doc},
01581   {"get_volumetric", (PyCFunction)py_mol_get_volumetric,
01582                      METH_VARARGS | METH_KEYWORDS, get_volumetric_doc},
01583   {"num_volumetric", (PyCFunction)py_mol_num_volumetric,
01584                      METH_VARARGS | METH_KEYWORDS, num_volumetric_doc},
01585   {"get_filenames", (PyCFunction)py_get_filenames, METH_VARARGS | METH_KEYWORDS, filenames_doc},
01586   {"get_filetypes", (PyCFunction)py_get_filetypes, METH_VARARGS | METH_KEYWORDS, filetypes_doc},
01587   {"get_databases", (PyCFunction)py_get_databases, METH_VARARGS | METH_KEYWORDS, databases_doc},
01588   {"get_accessions", (PyCFunction)py_get_accessions, METH_VARARGS | METH_KEYWORDS, accessions_doc},
01589   {"get_remarks", (PyCFunction)py_get_remarks, METH_VARARGS | METH_KEYWORDS, remarks_doc},
01590   {"get_periodic", (PyCFunction)py_get_periodic, METH_VARARGS | METH_KEYWORDS, get_periodic_doc},
01591   {"set_periodic", (PyCFunction)py_set_periodic, METH_VARARGS | METH_KEYWORDS, set_periodic_doc},
01592   {"get_visible", (PyCFunction)py_get_visible, METH_VARARGS | METH_KEYWORDS, get_visible_doc},
01593   {"set_visible", (PyCFunction)py_set_visible, METH_VARARGS | METH_KEYWORDS, set_visible_doc},
01594   {"get_physical_time", (PyCFunction)py_get_physical_time, METH_VARARGS | METH_KEYWORDS, time_doc},
01595   {"set_physical_time", (PyCFunction)py_set_physical_time, METH_VARARGS | METH_KEYWORDS, settime_doc},
01596 
01597   // Deprecated names, but still work for backwards compatibility
01598   {"remove_volumetric", (PyCFunction)py_mol_drm_volumetric,
01599                         METH_VARARGS | METH_KEYWORDS, del_volumetric_doc},
01600   {NULL, NULL}
01601 };
01602 
01603 static const char mol_moddoc[] =
01604 "Methods to interact with molecules, including loading topology, trajectory, "
01605 "or volumetric data, query the attributes of a molecule such as the number "
01606 "of frames or the physical time, or set the visibility of a molecule";
01607 
01608 #if PY_MAJOR_VERSION >= 3
01609 static struct PyModuleDef moleculedef = {
01610   PyModuleDef_HEAD_INIT,
01611   "molecule",
01612   mol_moddoc,
01613   -1,
01614   methods,
01615 };
01616 #endif
01617 
01618 PyObject* initmolecule(void) {
01619 #if PY_MAJOR_VERSION >= 3
01620   PyObject *module = PyModule_Create(&moleculedef);
01621 #else
01622   PyObject *module = Py_InitModule3("molecule", methods, mol_moddoc);
01623 #endif
01624   return module;
01625 }
01626 

Generated on Thu Mar 28 02:44:03 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002