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_measure.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.11 $ $Date: 2019年06月05日 14:50:54 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * Code to measure atom distances, angles, dihedrals, etc. 00019 ***************************************************************************/ 00020 00021 #include "py_commands.h" 00022 #include "VMDApp.h" 00023 #include "Measure.h" 00024 00025 static const char bond_doc[] = 00026 "Measures the distance between the atom1 and atom2 over the trajectory, either\n" 00027 "at the given frame or over frames from first to last. Distances between atoms\n" 00028 "in different molecules can be measured by giving specific molids\n\n" 00029 "Args:\n" 00030 " atom1 (int): Index of first atom\n" 00031 " atom2 (int): Index of second atom\n" 00032 " molid (int): Molecule ID of first atom, defaults to top molecule\n" 00033 " molid2 (int): Molecule ID of second atom, if different. (optional)\n" 00034 " frame (int): Measure distance in this single frame. Defaults to current\n" 00035 " first (int): For measuring multiple frames, first frame to measure\n" 00036 " last (int): For measuring multiple, last frame to measure\n" 00037 "Returns:\n" 00038 " (list of float): Distance between atoms for given frame(s)"; 00039 static PyObject *py_measure_bond(PyObject *self, PyObject *args, PyObject *kwargs) { 00040 const char *kwlist[] = {"atom1", "atom2", "molid", "molid2", "frame", "first", 00041 "last", NULL}; 00042 int first=-1, last=-1, frame=-1; 00043 PyObject *returnlist = NULL; 00044 int atmid[2], i; 00045 int molid[2] = {-1, -1}; 00046 00047 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|iiiii:measure.bond", 00048 (char**) kwlist, &atmid[0], &atmid[1], 00049 &molid[0], &molid[1], &frame, &first, &last)) 00050 return NULL; 00051 00052 VMDApp *app; 00053 if (!(app = get_vmdapp())) 00054 return NULL; 00055 00056 // If molid(s) unset, use top molecule 00057 if (molid[0] == -1) 00058 molid[0] = app->molecule_top(); 00059 00060 if (molid[1] == -1) 00061 molid[1] = molid[0]; 00062 00063 // Need either (first, last) or a single frame. 00064 if (frame != -1 && (first != -1 || last != -1)) { 00065 PyErr_Warn(PyExc_SyntaxWarning, "frame as well as first or last were " 00066 "specified.\nReturning value for just the " 00067 "frame"); 00068 first = -1; 00069 last = -1; 00070 } 00071 00072 //Calculate the bond length 00073 ResizeArray<float> gValues(1024); 00074 int ret_val = measure_geom(app->moleculeList, molid, atmid, &gValues, frame, 00075 first, last, molid[0], MEASURE_BOND); 00076 if (ret_val < 0) { 00077 PyErr_SetString(PyExc_RuntimeError, measure_error(ret_val)); 00078 return NULL; 00079 } 00080 00081 // Build the list containing all measured distances 00082 int numvalues = gValues.num(); 00083 if (!(returnlist = PyList_New(numvalues))) 00084 goto failure; 00085 00086 for (i = 0; i < numvalues; i++) { 00087 PyList_SET_ITEM(returnlist, i, PyFloat_FromDouble(gValues[i])); 00088 00089 // XXX this is inconsistent with the other two, why special? 00090 if (PyErr_Occurred()) 00091 goto failure; 00092 } 00093 return returnlist; 00094 00095 failure: 00096 PyErr_SetString(PyExc_ValueError, "Couldn't build list of distances"); 00097 Py_XDECREF(returnlist); 00098 return NULL; 00099 } 00100 00101 00102 static const char angle_doc[] = 00103 "Measure angles between given atoms over a trajectory. Can specify multiple\n" 00104 "molids to measure angles between atoms in different molecules.\n\n" 00105 "Args:\n" 00106 " atom1 (int): Index of first atom\n" 00107 " atom2 (int): Index of second atom\n" 00108 " atom3 (int): Index of third atom\n" 00109 " molid (int): Molecule ID of first atom. Defaults to top molecule\n" 00110 " molid2 (int): Molecule ID of second atom, if different from first molid\n" 00111 " molid3 (int): Molecule ID of third atom, if different from first molid\n" 00112 " frame (int): Single frame to measure angle in. Defaults to current frame\n" 00113 " first (int): First frame in range to measure in, for multiple frames\n" 00114 " last (int): Last frame in range to measure in, for multiple frames\n" 00115 "Returns:\n" 00116 " (list of float): Angle as measured in frame(s)"; 00117 static PyObject *py_measure_angle(PyObject *self, PyObject *args, PyObject *kwargs) { 00118 const char *kwlist[] = {"atom1", "atom2", "atom3", "molid", "molid2", 00119 "molid3", "frame", "first", "last", NULL}; 00120 int first=-1, last=-1, frame=-1; 00121 int molid[3] = {-1, -1, -1}; 00122 PyObject *returnlist; 00123 int atmid[3]; 00124 00125 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii|iiiiii:measure.angle", 00126 (char**) kwlist, &atmid[0], &atmid[1], 00127 &atmid[2], &molid[0], &molid[1], &molid[2], 00128 &frame, &first, &last)) 00129 return NULL; 00130 00131 VMDApp *app; 00132 if (!(app = get_vmdapp())) 00133 return NULL; 00134 00135 // Default to top molecule 00136 if (molid[0] == -1) 00137 molid[0] = app->molecule_top(); 00138 00139 // Other two molids default to the first molid 00140 if (molid[1] == -1) 00141 molid[1] = molid[0]; 00142 00143 if (molid[2] == -1) 00144 molid[2] = molid[0]; 00145 00146 // Warn if passing a single frame and a range 00147 if (frame != -1 && (first != -1 || last != -1)) { 00148 PyErr_Warn(PyExc_SyntaxWarning, "frame as well as first or last were " 00149 "specified.\nReturning value for just the " 00150 "frame"); 00151 first = -1; 00152 last = -1; 00153 } 00154 //Calculate the angle 00155 ResizeArray<float> gValues(1024); 00156 int ret_val = measure_geom(app->moleculeList, molid, atmid, &gValues, frame, 00157 first, last, molid[0], MEASURE_ANGLE); 00158 if (ret_val < 0) { 00159 PyErr_SetString(PyExc_RuntimeError, measure_error(ret_val)); 00160 return NULL; 00161 } 00162 00163 //Build the python list. 00164 int numvalues = gValues.num(); 00165 returnlist = PyList_New(numvalues); 00166 for (int i = 0; i < numvalues; i++) 00167 PyList_SetItem(returnlist, i, Py_BuildValue("f", gValues[i])); 00168 00169 // Remove reference to list if something went wrong 00170 if (PyErr_Occurred()) { 00171 PyErr_SetString(PyExc_ValueError, "Couldn't build list of angles"); 00172 Py_DECREF(returnlist); 00173 return NULL; 00174 } 00175 00176 return returnlist; 00177 } 00178 00179 00180 static const char dihed_doc[] = 00181 "Measures the dihedral angle between atoms over the trajectory. Can specify\n" 00182 "multiple molecule IDs to measure over different loaded molecules.\n\n" 00183 "Args:\n" 00184 " atom1 (int): First atom in dihedral\n" 00185 " atom2 (int): Second atom in dihedral\n" 00186 " atom3 (int): Third atom in dihedral\n" 00187 " atom4 (int): Fourth atom in dihedral\n" 00188 " molid (int): Molecule ID to measure in. Defaults to top molecule\n" 00189 " molid2 (int): Molecule ID for second atom, if different from molid\n" 00190 " molid3 (int): Molecule ID for third atom, if different from molid\n" 00191 " molid4 (int): Molecule ID for fourth atom, if different from molid\n" 00192 " frame (int): Single frame to measure angle in. Defaults to current frame\n" 00193 " first (int): First frame in range to measure in, for multiple frames\n" 00194 " last (int): Last frame in range to measure in, for multiple frames\n" 00195 "Returns:\n" 00196 " (list of float): Dihedral as measured in frame(s)"; 00197 static PyObject *py_measure_dihed(PyObject *self, PyObject *args, PyObject *kwargs) { 00198 const char *kwlist[] = {"atom1", "atom2", "atom3", "atom4", "molid", "molid2", 00199 "molid3", "molid4", "frame", "first", "last", NULL}; 00200 int first=-1, last=-1, frame=-1; 00201 int molid[4] = {-1, -1, -1, -1}; 00202 PyObject *returnlist; 00203 int atmid[4]; 00204 00205 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii|iiiiiii:measure.dihedral", 00206 (char**) kwlist, &atmid[0], &atmid[1], 00207 &atmid[2], &atmid[3], &molid[0], &molid[1], 00208 &molid[2], &molid[3], &frame, &first, &last)) 00209 return NULL; 00210 00211 VMDApp *app; 00212 if (!(app = get_vmdapp())) 00213 return NULL; 00214 00215 // Molid defaults to top molecule 00216 if (molid[0] == -1) 00217 molid[0] = app->molecule_top(); 00218 00219 // Other molecule IDs default to molid 00220 if (molid[1] == -1) 00221 molid[1] = molid[0]; 00222 00223 if (molid[2] == -1) 00224 molid[2] = molid[0]; 00225 00226 if (molid[3] == -1) 00227 molid[3] = molid[0]; 00228 00229 // Warn if both frame and range of frames are given 00230 if (frame != -1 && (first != -1 || last != -1)) { 00231 PyErr_Warn(PyExc_SyntaxWarning, "frame as well as first or last were " 00232 "specified.\nReturning value for just the " 00233 "frame"); 00234 first = -1; 00235 last = -1; 00236 } 00237 00238 //Calculate the dihedral angle 00239 ResizeArray<float> gValues(1024); 00240 int ret_val = measure_geom(app->moleculeList, molid, atmid, &gValues, frame, 00241 first, last, molid[0], MEASURE_DIHED); 00242 if (ret_val < 0) { 00243 PyErr_SetString(PyExc_RuntimeError, measure_error(ret_val)); 00244 return NULL; 00245 } 00246 00247 //Build the python list. 00248 int numvalues = gValues.num(); 00249 returnlist = PyList_New(numvalues); 00250 for (int i = 0; i < numvalues; i++) 00251 PyList_SetItem(returnlist, i, Py_BuildValue("f", gValues[i])); 00252 00253 // Remove reference to list if something went wrong 00254 if (PyErr_Occurred()) { 00255 PyErr_SetString(PyExc_ValueError, "Couldn't build list of dihedrals"); 00256 Py_DECREF(returnlist); 00257 return NULL; 00258 } 00259 00260 return returnlist; 00261 } 00262 00263 00264 static PyMethodDef methods[] = { 00265 {"bond", (PyCFunction)py_measure_bond, METH_VARARGS | METH_KEYWORDS, bond_doc}, 00266 {"angle", (PyCFunction)py_measure_angle, METH_VARARGS | METH_KEYWORDS, angle_doc}, 00267 {"dihedral", (PyCFunction)py_measure_dihed, METH_VARARGS | METH_KEYWORDS, dihed_doc}, 00268 {NULL, NULL} 00269 }; 00270 00271 00272 static const char measure_moddoc[] = 00273 "Methods to measure bonds, angles, or dihedrals in loaded molecules"; 00274 00275 00276 #if PY_MAJOR_VERSION >= 3 00277 static struct PyModuleDef measuredef = { 00278 PyModuleDef_HEAD_INIT, 00279 "measure", 00280 measure_moddoc, 00281 -1, 00282 methods, 00283 }; 00284 #endif 00285 00286 00287 PyObject* initmeasure() { 00288 #if PY_MAJOR_VERSION >= 3 00289 PyObject *m = PyModule_Create(&measuredef); 00290 #else 00291 PyObject *m = Py_InitModule3("measure", methods, measure_moddoc); 00292 #endif 00293 return m; 00294 }