static PyObject *getbonds(PyObject *self, PyObject *args) { int molid; PyObject *atomlist; if (!PyArg_ParseTuple(args, (char *)"iO!:getbonds", &molid, &PyTuple_Type, &atomlist)) return NULL; // bad args Molecule *mol = get_vmdapp()->moleculeList->mol_from_id(molid); if (!mol) { PyErr_SetString(PyExc_ValueError, "molecule no longer exists"); return NULL; } int num_atoms = mol->nAtoms; int num_selected = PyTuple_Size(atomlist); PyObject *newlist = PyList_New(num_selected); for (int i=0; i< num_selected; i++) { int id = PyInt_AsLong(PyTuple_GET_ITEM(atomlist, i)); if (PyErr_Occurred()) { Py_DECREF(newlist); return NULL; } if (id < 0 || id >= num_atoms) { PyErr_SetString(PyExc_ValueError, (char *)"invalid atom id found"); Py_DECREF(newlist); return NULL; } const MolAtom *atom = mol->atom(id); PyObject *bondlist = PyList_New(atom->bonds); for (int j=0; j<atom->bonds; j++) { PyList_SET_ITEM(bondlist, j, PyInt_FromLong(atom->bondTo[j])); } PyList_SET_ITEM(newlist, i, bondlist); } return newlist; }
// listall(category) - return a list of labels for the given label category. // labels will be returned as dictionary objects with the following keys: // molid, atomid, value, on. molid and atomid will be tuples, value will // be either a float or PyNone, and on will be 1 or 0. static PyObject *listall(PyObject *self, PyObject *args) { char *type; if (!PyArg_ParseTuple(args, (char *)"s:label.listall", &type)) return NULL; VMDApp *app = get_vmdapp(); int cat = app->geometryList->geom_list_index(type); if (cat < 0) { PyErr_SetString(PyExc_ValueError, (char *)"Unknown label category"); return NULL; } GeomListPtr glist = app->geometryList->geom_list(cat); int gnum = glist->num(); PyObject *newlist = PyList_New(gnum); for (int i=0; i<gnum; i++) { PyObject *obj = geom2dict((*glist)[i]); if (obj == NULL) { Py_DECREF(newlist); return NULL; } PyList_SET_ITEM(newlist, i, geom2dict((*glist)[i])); } return newlist; }
static PyObject *set_colormap(PyObject *self, PyObject *args) { char *name; PyObject *newdict; if (!PyArg_ParseTuple(args, (char *)"sO!", &name, &PyDict_Type, &newdict)) return NULL; VMDApp *app = get_vmdapp(); PyObject *keys = PyDict_Keys(newdict); PyObject *vals = PyDict_Values(newdict); int error = 0; for (int i=0; i<PyList_Size(keys); i++) { char *keyname = PyString_AsString(PyList_GET_ITEM(keys, i)); if (PyErr_Occurred()) { error = 1; break; } char *valname = PyString_AsString(PyList_GET_ITEM(vals, i)); if (PyErr_Occurred()) { error = 1; break; } if (!app->color_changename(name, keyname, valname)) { PyErr_SetString(PyExc_ValueError, (char *)"Invalid color category or item specified"); return NULL; } } Py_DECREF(keys); Py_DECREF(vals); if (error) return NULL; Py_INCREF(Py_None); return Py_None; }
static PyObject *sasa(PyObject *self, PyObject *args, PyObject *keywds) { int molid = -1, frame = -1; float srad = 0; PyObject *selobj = NULL, *restrictobj = NULL; int samples = -1; const int *sampleptr = NULL; PyObject *pointsobj = NULL; static char *kwlist[] = { (char *)"srad", (char *)"molid", (char *)"frame", (char *)"selected", (char *)"samples", (char *)"points", (char *)"restrict" }; if (!PyArg_ParseTupleAndKeywords(args, keywds, (char *)"fiiO!|iO!O!:atomselection.sasa", kwlist, &srad, &molid, &frame, &PyTuple_Type, &selobj, &samples, &PyList_Type, &pointsobj, &PyTuple_Type, &restrictobj)) return NULL; // validate srad if (srad < 0) { PyErr_SetString(PyExc_ValueError, (char *)"atomselect.sasa: srad must be non-negative."); return NULL; } // validate selection VMDApp *app = get_vmdapp(); AtomSel *sel = sel_from_py(molid, frame, selobj, app); if (!sel) return NULL; // fetch the radii and coordinates const float *radii = app->moleculeList->mol_from_id(sel->molid())->extraflt.data("radius"); const float *coords = sel->coordinates(app->moleculeList); // if samples was given and is valid, use it if (samples > 1) sampleptr = &samples; // if restrict is given, validate it AtomSel *restrictsel = NULL; if (restrictobj) { if (!(restrictsel = sel_from_py(molid, frame, restrictobj, app))) { delete sel; return NULL; } } // if points are requested, fetch them ResizeArray<float> sasapts; ResizeArray<float> *sasaptsptr = pointsobj ? &sasapts : NULL; // go! float sasa = 0; int rc = measure_sasa(sel, coords, radii, srad, &sasa, sasaptsptr, restrictsel, sampleptr); delete sel; delete restrictsel; if (rc) { PyErr_SetString(PyExc_ValueError, (char *)measure_error(rc)); return NULL; } // append surface points to the provided list object. if (pointsobj) { for (int i=0; i<sasapts.num(); i++) { PyList_Append(pointsobj, PyFloat_FromDouble(sasapts[i])); } } // return the total SASA. return PyFloat_FromDouble(sasa); }
static PyObject *get(PyObject *self, PyObject *args) { int i, molid, frame; PyObject *selected; int num_selected; char *attr = 0; // // get molid, list, and attribute // if (!PyArg_ParseTuple(args, (char *)"iiO!s", &molid, &frame, &PyTuple_Type, &selected, &attr)) return NULL; // bad args // // check molecule // VMDApp *app = get_vmdapp(); Molecule *mol = app->moleculeList->mol_from_id(molid); if (!mol) { PyErr_SetString(PyExc_ValueError, "molecule no longer exists"); return NULL; } const int num_atoms = mol->nAtoms; // // Check for a valid attribute // SymbolTable *table = app->atomSelParser; int attrib_index = table->find_attribute(attr); if (attrib_index == -1) { PyErr_SetString(PyExc_ValueError, "unknown atom attribute"); return NULL; } SymbolTableElement *elem = table->fctns.data(attrib_index); if (elem->is_a != SymbolTableElement::KEYWORD && elem->is_a != SymbolTableElement::SINGLEWORD) { PyErr_SetString(PyExc_ValueError, "attribute is not a keyword or singleword"); return NULL; } // // fetch the data // atomsel_ctxt context(table, mol, frame, attr); num_selected = PyTuple_Size(selected); PyObject *newlist = PyList_New(num_selected); // XXX should check that selected contains valid indices int *flgs = new int[num_atoms]; memset(flgs,0,num_atoms*sizeof(int)); for (i=0; i<num_selected; i++) flgs[PyInt_AsLong(PyTuple_GET_ITEM(selected,i))] = 1; if (elem->is_a == SymbolTableElement::SINGLEWORD) { int *tmp = new int[num_atoms]; memcpy(tmp, flgs, num_atoms*sizeof(int)); elem->keyword_single(&context, num_atoms, tmp); int j=0; for (i=0; i<num_atoms; i++) { if (flgs[i]) { if (tmp[i]) { PyList_SET_ITEM(newlist, j++, PyInt_FromLong(1)); } else { PyList_SET_ITEM(newlist, j++, PyInt_FromLong(0)); } } } delete [] tmp; } else { switch(table->fctns.data(attrib_index)->returns_a) { case (SymbolTableElement::IS_STRING): { const char **tmp= new const char *[num_atoms]; elem->keyword_string(&context, num_atoms, tmp, flgs); int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) { PyList_SET_ITEM(newlist, j++, PyString_FromString(tmp[i])); } } delete [] tmp; } break; case (SymbolTableElement::IS_INT): { int *tmp = new int[num_atoms]; elem->keyword_int(&context, num_atoms, tmp, flgs); int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) { PyList_SET_ITEM(newlist, j++, PyInt_FromLong(tmp[i])); } } delete [] tmp; } break; case (SymbolTableElement::IS_FLOAT): { double *tmp = new double[num_atoms]; elem->keyword_double(&context, num_atoms, tmp, flgs); int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) PyList_SET_ITEM(newlist, j++, PyFloat_FromDouble(tmp[i])); } delete [] tmp; } break; } // end switch } // end else delete [] flgs; return newlist; }
static PyObject *py_align(PyObject *self, PyObject *args) { int selmol, selframe, refmol, refframe, movemol, moveframe; PyObject *selobj, *refobj, *moveobj, *weightobj = NULL; if (!PyArg_ParseTuple(args, (char *)"iiO!iiO!iiO!O:atomselection.align", &selmol, &selframe, &PyTuple_Type, &selobj, &refmol, &refframe, &PyTuple_Type, &refobj, &movemol, &moveframe, &PyTuple_Type, &moveobj, &weightobj)) return NULL; // check if movemol is -1. If so, use the sel molecule and timestep instead if (movemol == -1) { movemol = selmol; moveobj = NULL; } VMDApp *app = get_vmdapp(); AtomSel *sel=NULL, *ref=NULL, *move=NULL; if (!(sel = sel_from_py(selmol, selframe, selobj, app)) || !(ref = sel_from_py(refmol, refframe, refobj, app)) || !(move = sel_from_py(movemol, moveframe, moveobj, app))) { delete sel; delete ref; delete move; return NULL; } const float *selts, *refts; float *movets; if (!(selts = sel->coordinates(app->moleculeList)) || !(refts = ref->coordinates(app->moleculeList)) || !(movets = move->coordinates(app->moleculeList))) { delete sel; delete ref; delete move; PyErr_SetString(PyExc_ValueError, "No coordinates in selection"); return NULL; } float *weight = parse_weight(sel, weightobj); if (!weight) { delete sel; delete ref; delete move; return NULL; } // Find the matrix that aligns sel with ref. Apply the transformation to // the atoms in move. // XXX need to add support for the "order" parameter as in Tcl. Matrix4 mat; int rc = measure_fit(sel, ref, selts, refts, weight, NULL, &mat); delete [] weight; delete sel; delete ref; if (rc < 0) { delete move; PyErr_SetString(PyExc_ValueError, (char *)measure_error(rc)); return NULL; } for (int i=0; i<move->num_atoms; i++) { if (move->on[i]) { float *pos = movets+3*i; mat.multpoint3d(pos, pos); } } Molecule *mol = app->moleculeList->mol_from_id(move->molid()); mol->force_recalc(DrawMolItem::MOL_REGEN); delete move; Py_INCREF(Py_None); return Py_None; }
static PyObject *set(PyObject *self, PyObject *args) { int i, molid, frame; PyObject *selected, *val; char *attr = 0; // // get molid, frame, list, attribute, and value // if (!PyArg_ParseTuple(args, (char *)"iiO!sO!", &molid, &frame, &PyTuple_Type, &selected, &attr, &PyTuple_Type, &val )) return NULL; // bad args // // check that we have been given either one value or one for each selected // atom // int num_selected = PyTuple_Size(selected); int tuplesize = PyTuple_Size(val); if (tuplesize != 1 && tuplesize != num_selected) { PyErr_SetString(PyExc_ValueError, "wrong number of items"); return NULL; } // // check molecule // VMDApp *app = get_vmdapp(); Molecule *mol = app->moleculeList->mol_from_id(molid); if (!mol) { PyErr_SetString(PyExc_ValueError, "molecule no longer exists"); return NULL; } const int num_atoms = mol->nAtoms; // // Check for a valid attribute // SymbolTable *table = app->atomSelParser; int attrib_index = table->find_attribute(attr); if (attrib_index == -1) { PyErr_SetString(PyExc_ValueError, "unknown atom attribute"); return NULL; } SymbolTableElement *elem = table->fctns.data(attrib_index); if (elem->is_a != SymbolTableElement::KEYWORD && elem->is_a != SymbolTableElement::SINGLEWORD) { PyErr_SetString(PyExc_ValueError, "attribute is not a keyword or singleword"); return NULL; } if (!table->is_changeable(attrib_index)) { PyErr_SetString(PyExc_ValueError, "attribute is not modifiable"); return NULL; } // // convert the list of selected atoms into an array of integer flags // // XXX should check that selected contains valid indices int *flgs = new int[num_atoms]; memset(flgs,0,num_atoms*sizeof(int)); for (i=0; i<num_selected; i++) flgs[PyInt_AsLong(PyTuple_GET_ITEM(selected,i))] = 1; // // set the data // // singlewords can never be set, so macro is NULL. atomsel_ctxt context(table, mol, frame, NULL); if (elem->returns_a == SymbolTableElement::IS_INT) { int *list = new int[num_atoms]; if (tuplesize > 1) { int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyInt_AsLong(PyTuple_GET_ITEM(val, j++)); } } else { for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyInt_AsLong(PyTuple_GET_ITEM(val, 0)); } } elem->set_keyword_int(&context, num_atoms, list, flgs); delete [] list; } else if (elem->returns_a == SymbolTableElement::IS_FLOAT) { double *list = new double[num_atoms]; if (tuplesize > 1) { int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(val, j++)); } } else { for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(val, 0)); } } elem->set_keyword_double(&context, num_atoms, list, flgs); delete [] list; } else if (elem->returns_a == SymbolTableElement::IS_STRING) { const char **list = new const char *[num_atoms]; if (tuplesize > 1) { int j=0; for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyString_AsString(PyTuple_GET_ITEM(val, j++)); } } else { for (int i=0; i<num_atoms; i++) { if (flgs[i]) list[i] = PyString_AsString(PyTuple_GET_ITEM(val, 0)); } } elem->set_keyword_string(&context, num_atoms, list, flgs); delete [] list; } // Recompute the color assignments if certain atom attributes are changed. if (!strcmp(attr, "name") || !strcmp(attr, "type") || !strcmp(attr, "resname") || !strcmp(attr, "chain") || !strcmp(attr, "segid") || !strcmp(attr, "segname")) app->moleculeList->add_color_names(molid); mol->force_recalc(DrawMolItem::SEL_REGEN | DrawMolItem::COL_REGEN); delete [] flgs; Py_INCREF(Py_None); return Py_None; }
void initvmd() { // Assume that VMD should not initialize or use MPI // It is conceivable we would want to be able to load the VMD // Python module into a MPI-based Python run, and enable the // MPI features of VMD, but we'll have to determine the best way // to detect this and it will need to be tested since we may have // to handle this case differently than the normal MPI case where // VMD explicitly does MPI initialization and shutdown itself. int mpienabled = 0; // If there's already a VMDapp in get_vmdapp, then we must be running // inside a standalone VMD instead of being loaded as a python extension. // Don't throw an error - just load the methods for interoperability // in case vmd.so is in the PYTHONPATH of the standalone application. if (get_vmdapp() != NULL) { (void)Py_InitModule((char *)"vmd", VMDAppMethods); return; } int argc=1; char *argv[1]; argv[0] = Py_GetProgramFullPath(); if (!VMDinitialize(&argc, (char ***) &argv, mpienabled)) { return; } // XXX this is a hack, and it would be better to tie this into // VMDApp more directly at some later point, but the regular // VMD startup code is similarly lame, so we'll use it for now. const char *disp = getenv("VMDDISPLAYDEVICE"); if (!disp) disp="text"; int loc[2] = { 50, 50 }; int size[2] = { 400, 400 }; VMDgetDisplayFrame(loc, size); VMDApp *app = new VMDApp(1, argv, mpienabled); app->VMDinit(1, argv, disp, loc, size); // read application defaults VMDreadInit(app); // read user-defined startup files VMDreadStartup(app); set_vmdapp(app); // set my local static the_app = app; PyObject *vmdmodule = Py_InitModule((char *)"vmd", VMDAppMethods); initanimate(); initatomsel(); initaxes(); initcolor(); initdisplay(); initgraphics(); initimd(); initlabel(); initmaterial(); initmolecule(); initmolrep(); initmouse(); initrender(); inittrans(); initvmdmenu(); #ifdef VMDNUMPY initvmdnumpy(); #endif if (PyErr_Occurred()) return; static const char *modules[] = { "animate", "atomsel", "axes", "color", "display", "graphics", "imd", "label", "material", "molecule", "molrep", "mouse", "render", "trans", "vmdmenu", "vmdnumpy" }; for (unsigned i=0; i<sizeof(modules)/sizeof(const char *); i++) { const char *m = modules[i]; #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 5) #define CAST_HACK (char *) #else #define CAST_HACK #endif PyModule_AddObject(vmdmodule, CAST_HACK m, PyImport_ImportModule( CAST_HACK m)); } event_tstate = PyThreadState_Get(); #if defined(VMD_SHARED) PyOS_InputHook = vmd_input_hook; #endif }
static PyObject *contacts(PyObject *self, PyObject *args) { int mol1, frame1, mol2, frame2; PyObject *selected1, *selected2; float cutoff; if (!PyArg_ParseTuple(args, (char *)"iiO!iiO!f:atomselection.contacts", &mol1, &frame1, &PyTuple_Type, &selected1, &mol2, &frame2, &PyTuple_Type, &selected2, &cutoff)) return NULL; VMDApp *app = get_vmdapp(); AtomSel *sel1 = sel_from_py(mol1, frame1, selected1, app); AtomSel *sel2 = sel_from_py(mol2, frame2, selected2, app); if (!sel1 || !sel2) { delete sel1; delete sel2; return NULL; } const float *ts1 = sel1->coordinates(app->moleculeList); const float *ts2 = sel2->coordinates(app->moleculeList); if (!ts1 || !ts2) { PyErr_SetString(PyExc_ValueError, "No coordinates in selection"); delete sel1; delete sel2; return NULL; } Molecule *mol = app->moleculeList->mol_from_id(mol1); GridSearchPair *pairlist = vmd_gridsearch3( ts1, sel1->num_atoms, sel1->on, ts2, sel2->num_atoms, sel2->on, cutoff, -1, (sel1->num_atoms + sel2->num_atoms) * 27); delete sel1; delete sel2; GridSearchPair *p, *tmp; PyObject *list1 = PyList_New(0); PyObject *list2 = PyList_New(0); PyObject *tmp1; PyObject *tmp2; for (p=pairlist; p != NULL; p=tmp) { // throw out pairs that are already bonded MolAtom *a1 = mol->atom(p->ind1); if (mol1 != mol2 || !a1->bonded(p->ind2)) { // Needed to avoid a memory leak. Append increments the refcount // of whatever gets added to it, but so does PyInt_FromLong. // Without a decref, the integers created never have their refcount // go to zero, and you leak memory. tmp1 = PyInt_FromLong(p->ind1); tmp2 = PyInt_FromLong(p->ind2); PyList_Append(list1, tmp1); PyList_Append(list2, tmp2); Py_DECREF(tmp1); Py_DECREF(tmp2); } tmp = p->next; free(p); } PyObject *result = PyList_New(2); PyList_SET_ITEM(result, 0, list1); PyList_SET_ITEM(result, 1, list2); return result; }
static PyObject* py_set_colors(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject *newdict, *newtuple, *keys, *vals; const char *kwnames[] = {"colors", NULL}; PyObject *retval = NULL; char *keyname; float rgb[3]; VMDApp *app; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:color.set_colors", (char**) kwnames, &PyDict_Type, &newdict)) return NULL; if (!(app = get_vmdapp())) return NULL; keys = PyDict_Keys(newdict); vals = PyDict_Values(newdict); for (int i=0; i<PyList_Size(keys); i++) { // Get color name from input dictionary keyname = as_charptr(PyList_GetItem(keys, i)); if (PyErr_Occurred()) goto cleanup; // Check this color name actually exists if (app->color_index(keyname) < 0) { PyErr_Format(PyExc_ValueError, "Unknown color '%s'", keyname); goto cleanup; } // Unpack value tuples into 3 floats newtuple = PyList_GetItem(vals, i); if (!PyTuple_Check(newtuple) || PyTuple_Size(newtuple) != 3) { PyErr_SetString(PyExc_ValueError, "color definition must be 3-tuple of floats"); goto cleanup; } for (int j=0; j<3; j++) { rgb[j] = (float)PyFloat_AsDouble(PyTuple_GET_ITEM(newtuple, j)); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "color definition must be floats"); goto cleanup; } } // Finally actually change the color app->color_change_rgb(keyname, rgb[0], rgb[1], rgb[2]); } retval = Py_None; // Getting the keys and values from the dictionary makes a new reference. // We tell Python we're done with it so as to not leak memory. // This needs to happen even if there was a problem setting color, which is // why we don't return NULL from the error checking statements above. cleanup: Py_DECREF(keys); Py_DECREF(vals); Py_XINCREF(retval); return retval; }
static PyObject *imdconnected(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, (char *)"")) return NULL; VMDApp *app = get_vmdapp(); return Py_BuildValue( "O", app->imdMgr->connected() ? Py_True : Py_False ); }