00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "py_commands.h"
00022 #include "VMDApp.h"
00023 #include "Molecule.h"
00024 #include "MoleculeList.h"
00025 #include "DrawMolecule.h"
00026
00027 static const char bond_doc[] = "Get all unique bonds within a specified molecule. Optionally, can get bond\n"
00028 "type and order by modifying the type parameter\n\n"
00029 "Args:\n"
00030 " molid (int): Molecule ID to query. Defaults to top molecule\n"
00031 " type (bool): Whether to include bond type information in the result\n"
00032 " Defaults to False.\n"
00033 " orders (bool): Whether to include bond order information in the result\n"
00034 " Defaults to False.\n"
00035 "Returns:\n"
00036 " (list of lists) Information about each bond in the system. Each bond\n"
00037 " will be a list with the indices of the two atoms in the\n"
00038 " bond, followed by bond type (as a string) and order (as a float) if\n"
00039 " requested";
00040 static PyObject* topo_get_bond(PyObject *self, PyObject *args, PyObject *kwargs) {
00041 const char *kwlist[] = {"molid", "type", "order", NULL};
00042 PyObject *returnlist = NULL, *bond = NULL;
00043 int b_types = 0, b_orders = 0, molid = -1;
00044 PyObject *obtypes = Py_False;
00045 int i, j, types;
00046 Molecule *mol;
00047
00048 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOO&:topology.bonds",
00049 (char**) kwlist, &molid, &obtypes,
00050 convert_bool, &b_orders))
00051 return NULL;
00052
00053 VMDApp *app;
00054 if (!(app = get_vmdapp()))
00055 return NULL;
00056
00057
00058 if (molid == -1)
00059 molid = app->molecule_top();
00060
00061 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00062 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00063 return NULL;
00064 }
00065
00066 if (PyBool_Check(obtypes)) {
00067 b_types = (obtypes == Py_True) ? 1 : 0;
00068
00069
00070 } else if (is_pyint(obtypes)) {
00071
00072 if (kwargs && PyDict_GetItemString(kwargs, "order")) {
00073 PyErr_SetString(PyExc_ValueError, "Cannot specify deprecated type "
00074 "argument with new or orders arguments");
00075 return NULL;
00076 }
00077 types = as_int(obtypes);
00078
00079 if (types == 3)
00080 b_types = b_orders = 1;
00081 else if (types == 2)
00082 b_orders = 1;
00083 else if (types == 1)
00084 b_types = 1;
00085
00086 PyErr_Warn(PyExc_DeprecationWarning, "type int keyword is now replaced by "
00087 "type and order booleans");
00088
00089 } else {
00090 PyErr_SetString(PyExc_TypeError, "type keyword expected a bool");
00091 return NULL;
00092 }
00093
00094
00095
00096 if (!(returnlist = PyList_New(0)))
00097 goto failure;
00098
00099 for (i = 0; i < mol->nAtoms - 1; i++) {
00100 const MolAtom *atom = mol->atom(i);
00101 for (j = 0; j < atom->bonds; j++) {
00102 if (i < atom->bondTo[j]) {
00103 if (b_types && b_orders) {
00104 bond = Py_BuildValue("iisf", i, atom->bondTo[j],
00105 mol->bondTypeNames.name(mol->getbondtype(i, j)),
00106 mol->getbondorder(i, j));
00107 } else if (b_types) {
00108 bond = Py_BuildValue("iis", i, atom->bondTo[j],
00109 mol->bondTypeNames.name(mol->getbondtype(i, j)));
00110 } else if (b_orders) {
00111 bond = Py_BuildValue("iif", i, atom->bondTo[j],
00112 mol->getbondorder(i, j));
00113 } else {
00114 bond = Py_BuildValue("ii", i, atom->bondTo[j]);
00115 }
00116
00117
00118 PyList_Append(returnlist, bond);
00119 Py_XDECREF(bond);
00120 if (PyErr_Occurred())
00121 goto failure;
00122 }
00123 }
00124 }
00125 return returnlist;
00126
00127 failure:
00128 PyErr_SetString(PyExc_RuntimeError, "problem building bond list");
00129 Py_XDECREF(returnlist);
00130 return NULL;
00131 }
00132
00133
00134 static const char angle_doc[] =
00135 "Get all unique angles within a specified molecule. Optionally, can get angle\n"
00136 "type as well\n\n"
00137 "Args:\n"
00138 " molid (int): Molecule ID to query. Defaults to top molecule\n"
00139 " type (bool): Whether to include angle type information in the result\n"
00140 " Defaults to False.\n"
00141 "Returns:\n"
00142 " (list of lists) Information about each angle in the system. Each angle \n"
00143 " will be a list with the indices of the three atoms comprising the\n"
00144 " angle, followed by angle type (as a string) if requested.";
00145 static PyObject* topo_get_angle(PyObject *self, PyObject *args,
00146 PyObject *kwargs) {
00147 const char *kwlist[] = {"molid", "type", NULL};
00148 PyObject *returnlist = NULL;
00149 int molid = -1, types = 0;
00150 Molecule *mol;
00151 int i;
00152
00153 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:topology.angle",
00154 (char**) kwlist, &molid, &types))
00155 return NULL;
00156
00157 VMDApp *app;
00158 if (!(app = get_vmdapp()))
00159 return NULL;
00160
00161 if (molid == -1)
00162 molid = app->molecule_top();
00163
00164 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00165 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00166 return NULL;
00167 }
00168
00169 if (!(returnlist = PyList_New(mol->num_angles())))
00170 goto failure;
00171
00172 for (i=0; i<mol->num_angles(); i++) {
00173 PyObject* angle;
00174 if (types) {
00175 angle = Py_BuildValue("iiis", mol->angles[3*i], mol->angles[3*i+1],
00176 mol->angles[3*i+2],
00177 mol->angleTypeNames.name(mol->get_angletype(i)));
00178 } else {
00179 angle = Py_BuildValue("iii", mol->angles[3*i], mol->angles[3*i+1],
00180 mol->angles[3*i+2]);
00181 }
00182 PyList_SET_ITEM(returnlist, i, angle);
00183 if (PyErr_Occurred())
00184 goto failure;
00185 }
00186 return returnlist;
00187
00188 failure:
00189 PyErr_SetString(PyExc_RuntimeError, "problem building angle list");
00190 Py_XDECREF(returnlist);
00191 return NULL;
00192 }
00193
00194
00195 static const char dihed_doc[] =
00196 "Get all unique dihedrals within a specified molecule. Optionally, can get\n"
00197 "dihedral type as well\n\n"
00198 "Args:\n"
00199 " molid (int): Molecule ID to query. Defaults to top molecule\n"
00200 " type (bool): Whether to include dihedral type information in the result\n"
00201 " Defaults to False.\n"
00202 "Returns:\n"
00203 " (list of lists) Information about each dihedral in the system. Each\n"
00204 " dihedral will be a list with the indices of the four atoms\n"
00205 " comprising the dihedral, followed by dihedral type (as a string) if\n"
00206 " requested.";
00207 static PyObject* topo_get_dihed(PyObject *self, PyObject *args,
00208 PyObject *kwargs) {
00209 const char *kwlist[] = {"molid", "type", NULL};
00210 PyObject *returnlist = NULL;
00211 int molid = -1, types = 0;
00212 Molecule *mol;
00213 int i;
00214
00215 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:topology.dihedral",
00216 (char**) kwlist, &molid, &types))
00217 return NULL;
00218
00219 VMDApp *app;
00220 if (!(app = get_vmdapp()))
00221 return NULL;
00222
00223 if (molid == -1)
00224 molid = app->molecule_top();
00225
00226 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00227 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00228 return NULL;
00229 }
00230
00231 if (!(returnlist = PyList_New(mol->num_dihedrals())))
00232 goto failure;
00233
00234 for (i = 0; i < mol->num_dihedrals(); i++) {
00235 PyObject* dihed;
00236 if (types) {
00237 dihed = Py_BuildValue("iiiis",
00238 mol->dihedrals[4*i], mol->dihedrals[4*i+1],
00239 mol->dihedrals[4*i+2], mol->dihedrals[4*i+3],
00240 mol->dihedralTypeNames.name(mol->get_dihedraltype(i)));
00241 } else {
00242 dihed = Py_BuildValue("iiii",
00243 mol->dihedrals[4*i], mol->dihedrals[4*i+1],
00244 mol->dihedrals[4*i+2], mol->dihedrals[4*i+3]);
00245 }
00246 PyList_SET_ITEM(returnlist, i, dihed);
00247 if (PyErr_Occurred())
00248 goto failure;
00249 }
00250 return returnlist;
00251
00252 failure:
00253 PyErr_SetString(PyExc_RuntimeError, "Problem building dihedral list");
00254 Py_XDECREF(returnlist);
00255 return NULL;
00256 }
00257
00258
00259 static const char impropers_doc[] =
00260 "Get all unique impropers within a specified molecule. Optionally, can get\n"
00261 "improper type as well\n\n"
00262 "Args:\n"
00263 " molid (int): Molecule ID to query. Defaults to top molecule\n"
00264 " type (bool): Whether to include improper type information in the result\n"
00265 " Defaults to False.\n"
00266 "Returns:\n"
00267 " (list of lists) Information about each improper in the system. Each\n"
00268 " improper will be a list with the indices of the four atoms\n"
00269 " comprising the improper, followed by improper type (as a string) if\n"
00270 " requested.";
00271 static PyObject* topo_get_impro(PyObject *self, PyObject *args,
00272 PyObject *kwargs) {
00273 const char *kwlist[] = {"molid", "type", NULL};
00274 PyObject *returnlist = NULL;
00275 int molid = -1, types = 0;
00276 Molecule *mol;
00277 int i;
00278
00279 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:topology.impropers",
00280 (char**) kwlist, &molid, &types))
00281 return NULL;
00282
00283 VMDApp *app;
00284 if (!(app = get_vmdapp()))
00285 return NULL;
00286
00287 if (molid == -1)
00288 molid = app->molecule_top();
00289
00290 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00291 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00292 return NULL;
00293 }
00294
00295 if (!(returnlist = PyList_New(mol->num_impropers())))
00296 goto failure;
00297
00298 for (i = 0; i < mol->num_impropers(); i++) {
00299 PyObject* improper;
00300 if (types) {
00301 improper = Py_BuildValue("iiiis",
00302 mol->impropers[4*i], mol->impropers[4*i+1],
00303 mol->impropers[4*i+2], mol->impropers[4*i+3],
00304 mol->improperTypeNames.name(mol->get_impropertype(i)));
00305 } else {
00306 improper = Py_BuildValue("iiii",
00307 mol->impropers[4*i], mol->impropers[4*i+1],
00308 mol->impropers[4*i+2], mol->impropers[4*i+3]);
00309 }
00310 PyList_SetItem(returnlist, i, improper);
00311 }
00312 return returnlist;
00313
00314 failure:
00315 PyErr_SetString(PyExc_RuntimeError, "Problem building improper list");
00316 Py_XDECREF(returnlist);
00317 return NULL;
00318 }
00319
00320
00321 static const char addbond_doc[] =
00322 "Add a bond between two atoms with given indices. If bond is already present,\n"
00323 "nothing will be done.\n\n"
00324 "Args:\n"
00325 " i (int): Index of first atom\n"
00326 " j (int): Index of second atom\n"
00327 " molid (int): Molecule ID to add bond to. Defaults to top molecule.\n"
00328 " order (float): Bond order. Defaults to 1.0\n"
00329 " type (str): Bond type. Can be from output of `topology.bondtypes()`,\n"
00330 " or can define a new bond type. Defaults to None";
00331 static PyObject* topo_add_bond(PyObject *self, PyObject *args, PyObject *kwargs) {
00332 const char *kwlist[] = {"i", "j", "molid", "order", "type", NULL};
00333 int molid = -1, type = -1;
00334 char *bondtype = NULL;
00335 float order = 1.0;
00336 Molecule *mol;
00337 int i, j;
00338
00339 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ifz:topology.addbond",
00340 (char**) kwlist, &i, &j, &molid, &order,
00341 &bondtype))
00342 return NULL;
00343
00344 VMDApp *app;
00345 if (!(app = get_vmdapp()))
00346 return NULL;
00347
00348 if (molid == -1)
00349 molid = app->molecule_top();
00350
00351 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00352 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00353 return NULL;
00354 }
00355
00356
00357 if (bondtype) {
00358 type = mol->bondTypeNames.add_name(bondtype, 0);
00359 mol->set_dataset_flag(BaseMolecule::BONDTYPES);
00360 }
00361
00362 mol->set_dataset_flag(BaseMolecule::BONDS);
00363 mol->set_dataset_flag(BaseMolecule::BONDORDERS);
00364
00365 if (mol->add_bond_dupcheck(i, j, order, type)) {
00366 PyErr_Format(PyExc_RuntimeError, "Problem adding bond between atoms %d "
00367 "and %d on molid %d", i, j, molid);
00368 return NULL;
00369 }
00370
00371 Py_INCREF(Py_None);
00372 return Py_None;
00373 }
00374
00375
00376 static const char addangle_doc[] =
00377 "Add an angle between three atoms with given indices. No checking for\n"
00378 "duplicate angles is performed\n\n"
00379 "Args:\n"
00380 " i (int): Index of first atom\n"
00381 " j (int): Index of second atom\n"
00382 " k (int): Index of third atom\n"
00383 " molid (int): Molecule ID to add angle to. Defaults to top molecule.\n"
00384 " type (str): Angle type. Can be from output of `topology.getangletypes()`,\n"
00385 " or can define a new angle type. Defaults to None\n"
00386 "Returns:\n"
00387 " (int) Index of new angle in system";
00388 static PyObject* topo_add_angle(PyObject *self, PyObject *args,
00389 PyObject *kwargs) {
00390 const char *kwlist[] = {"i", "j", "k", "molid", "type", NULL};
00391 int molid = -1, type = -1;
00392 char *angletype = NULL;
00393 Molecule *mol;
00394 int i, j, k;
00395
00396 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii|iz:topology.addangle",
00397 (char**) kwlist, &i, &j, &k, &molid,
00398 &angletype))
00399 return NULL;
00400
00401 VMDApp *app;
00402 if (!(app = get_vmdapp()))
00403 return NULL;
00404
00405 if (molid == -1)
00406 molid = app->molecule_top();
00407
00408 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00409 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00410 return NULL;
00411 }
00412
00413 if (angletype) {
00414 type = mol->angleTypeNames.add_name(angletype, 0);
00415
00416 mol->set_dataset_flag(BaseMolecule::ANGLETYPES);
00417 }
00418 mol->set_dataset_flag(BaseMolecule::ANGLES);
00419
00420 return as_pyint(mol->add_angle(i, j, k, type));
00421 }
00422
00423
00424 static const char adddihed_doc[] =
00425 "Add a dihedral between four atoms with the given indices. No checking for\n"
00426 "duplicate dihedrals is performed.\n\n"
00427 "Args:\n"
00428 " i (int): Index of first atom\n"
00429 " j (int): Index of second atom\n"
00430 " k (int): Index of third atom\n"
00431 " l (int): Index of fourth atom\n"
00432 " molid (int): Molecule ID to add dihedral in. Defaults to top molecule.\n"
00433 " type (str): Angle type. Can be from output of `topology.getangletypes()`,\n"
00434 " or can define a new angle type. Defaults to None\n"
00435 "Returns:\n"
00436 " (int) New number of dihedrals defined in system";
00437 static PyObject* topo_add_dihed(PyObject *self, PyObject *args,
00438 PyObject *kwargs) {
00439 const char *kwlist[] = {"i", "j", "k", "l", "molid", "type", NULL};
00440 int molid = -1, type = -1;
00441 char *dihetype = NULL;
00442 int i, j, k, l;
00443 Molecule *mol;
00444
00445 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii|iz:topology.adddihedral",
00446 (char**) kwlist, &i, &j, &k, &l, &molid,
00447 &dihetype))
00448 return NULL;
00449
00450 VMDApp *app;
00451 if (!(app = get_vmdapp()))
00452 return NULL;
00453
00454 if (molid == -1)
00455 molid = app->molecule_top();
00456
00457 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00458 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00459 return NULL;
00460 }
00461
00462 if (dihetype) {
00463 type = mol->dihedralTypeNames.add_name(dihetype, 0);
00464
00465
00466 mol->set_dataset_flag(BaseMolecule::ANGLETYPES);
00467 }
00468 mol->set_dataset_flag(BaseMolecule::ANGLES);
00469
00470 return as_pyint(mol->add_dihedral(i, j, k, l, type));
00471 }
00472
00473
00474 static const char addimproper_doc[] =
00475 "Add an improper dihedral between four atoms with the given indices. No\n"
00476 "checking for duplicate impropers is performed.\n\n"
00477 "Args:\n"
00478 " i (int): Index of first atom\n"
00479 " j (int): Index of second atom\n"
00480 " k (int): Index of third atom\n"
00481 " l (int): Index of fourth atom\n"
00482 " molid (int): Molecule ID to add dihedral in. Defaults to top molecule.\n"
00483 " type (str): Angle type. Can be from output of `topology.getangletypes()`,\n"
00484 " or can define a new angle type. Defaults to None\n"
00485 "Returns:\n"
00486 " (int) New number of improper dihedrals defined in system";
00487 static PyObject* topo_add_improp(PyObject *self, PyObject *args,
00488 PyObject *kwargs) {
00489 const char *kwlist[] = {"i", "j", "k", "l", "molid", "type", NULL};
00490 int molid = -1, type = -1;
00491 char *dihetype = NULL;
00492 int i, j, k, l;
00493 Molecule *mol;
00494
00495 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii|iz:topology.addimproper",
00496 (char**) kwlist, &i, &j, &k, &l, &molid,
00497 &dihetype))
00498 return NULL;
00499
00500 VMDApp *app;
00501 if (!(app = get_vmdapp()))
00502 return NULL;
00503
00504 if (molid == -1)
00505 molid = app->molecule_top();
00506
00507 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00508 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00509 return NULL;
00510 }
00511
00512 if (dihetype) {
00513 type = mol->improperTypeNames.add_name(dihetype, 0);
00514
00515
00516 mol->set_dataset_flag(BaseMolecule::ANGLETYPES);
00517 }
00518 mol->set_dataset_flag(BaseMolecule::ANGLES);
00519
00520 return as_pyint(mol->add_improper(i, j, k, l, type));
00521 }
00522
00523
00524 static const char delbond_doc[] =
00525 "Delete a bond between atoms with the given indices. If the bond does not\n"
00526 "exist, does nothing.\n\n"
00527 "Args:\n"
00528 " i (int): Index of first atom\n"
00529 " j (int): Index of second atom\n"
00530 " molid (int): Molecule ID to delete bond from. Defaults to top molecule.\n"
00531 "Returns:\n"
00532 " (bool) True if bond exists and was deleted";
00533 static PyObject* topo_del_bond(PyObject *self, PyObject *args, PyObject *kwargs) {
00534 const char *kwlist[] = {"i", "j", "molid", NULL};
00535 PyObject *result = Py_False;
00536 MolAtom *atomi, *atomj;
00537 float *bondOrders;
00538 int molid = -1;
00539 int *bondTypes;
00540 Molecule *mol;
00541 int i, j, tmp;
00542
00543 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:topology.delbond",
00544 (char**) kwlist, &i, &j, &molid))
00545 return NULL;
00546
00547 VMDApp *app;
00548 if (!(app = get_vmdapp()))
00549 return NULL;
00550
00551 if (molid == -1)
00552 molid = app->molecule_top();
00553
00554 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00555 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00556 return NULL;
00557 }
00558
00559 if (i < 0 || j < 0 || i >= mol->nAtoms || j >= mol->nAtoms) {
00560 PyErr_Format(PyExc_ValueError, "invalid bond atom indices '%d'-'%d'", i, j);
00561 return NULL;
00562 }
00563
00564 bondOrders = mol->extraflt.data("bondorders");
00565 bondTypes = mol->extraint.data("bondtypes");
00566 atomi = mol->atom(i);
00567 atomj = mol->atom(j);
00568
00569 for (tmp = 0; tmp < atomi->bonds && j != atomi->bondTo[tmp]; tmp++);
00570
00571
00572 if (tmp < atomi->bonds) {
00573 atomi->bondTo[tmp] = atomi->bondTo[--atomi->bonds];
00574 mol->set_dataset_flag(BaseMolecule::BONDS);
00575
00576 if (bondOrders) {
00577 bondOrders[i * MAXATOMBONDS + tmp] = bondOrders[i * MAXATOMBONDS + atomi->bonds];
00578 bondOrders[i * MAXATOMBONDS + atomi->bonds] = 1.0;
00579 mol->set_dataset_flag(BaseMolecule::BONDORDERS);
00580 }
00581
00582 if (bondTypes) {
00583 bondTypes[i * MAXATOMBONDS + tmp] = bondTypes[i * MAXATOMBONDS + atomi->bonds];
00584 bondTypes[i * MAXATOMBONDS + atomi->bonds] = -1;
00585 mol->set_dataset_flag(BaseMolecule::BONDTYPES);
00586 }
00587
00588 for (tmp = 0; tmp < atomj->bonds && i != atomj->bondTo[tmp]; tmp++);
00589 atomj->bondTo[tmp] = atomj->bondTo[--atomj->bonds];
00590
00591 result = Py_True;
00592 }
00593
00594 Py_INCREF(result);
00595 return result;
00596 }
00597
00598
00599 static const char delangle_doc[] =
00600 "Delete an angle between atoms with the given indices. If the angle does not\n"
00601 "exist, does nothing.\n\n"
00602 "Args:\n"
00603 " i (int): Index of first atom\n"
00604 " j (int): Index of second atom\n"
00605 " k (int): Index of third atom\n"
00606 " molid (int): Molecule ID to delete from. Defaults to top molecule.\n"
00607 "Returns:\n"
00608 " (bool) True if angle exists and was deleted";
00609 static PyObject* topo_del_angle(PyObject *self, PyObject *args,
00610 PyObject *kwargs) {
00611 const char *kwlist[] = {"i", "j", "k", "molid", NULL};
00612 PyObject *result = Py_False;
00613 int molid = -1;
00614 int i, j, k, s;
00615 Molecule *mol;
00616
00617 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii|i:topology:delangle",
00618 (char**) kwlist, &i, &j, &k, &molid))
00619 return NULL;
00620
00621 VMDApp *app;
00622 if (!(app = get_vmdapp()))
00623 return NULL;
00624
00625 if (molid == -1)
00626 molid = app->molecule_top();
00627
00628 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00629 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00630 return NULL;
00631 }
00632
00633 if (i < 0 || j < 0 || k < 0 ||
00634 k >= mol->nAtoms || i >= mol->nAtoms || j >= mol->nAtoms) {
00635 PyErr_Format(PyExc_ValueError, "invalid angle atom indices %d-%d-%d",
00636 i, j, k);
00637 return NULL;
00638 }
00639
00640
00641 if (i > k) {
00642 s = k;
00643 k = i;
00644 i = s;
00645 }
00646
00647 s = mol->num_angles();
00648 for (int tmp = 0; tmp < s; tmp++) {
00649 if (i == mol->angles[3*tmp ] &&
00650 j == mol->angles[3*tmp+1] &&
00651 k == mol->angles[3*tmp+2]) {
00652 mol->angles[3*tmp ] = mol->angles[3*s-3];
00653 mol->angles[3*tmp+1] = mol->angles[3*s-2];
00654 mol->angles[3*tmp+2] = mol->angles[3*s-1];
00655
00656 if (mol->angleTypes.num() > tmp) {
00657 if (mol->angleTypes.num() == s)
00658 mol->angleTypes[tmp] = mol->angleTypes[s-1];
00659 else
00660 mol->angleTypes[tmp] = -1;
00661 }
00662
00663 mol->angles.pop();
00664 mol->angles.pop();
00665 mol->angles.pop();
00666 mol->set_dataset_flag(BaseMolecule::ANGLES);
00667 result = Py_True;
00668 break;
00669 }
00670 }
00671
00672 Py_INCREF(result);
00673 return result;
00674 }
00675
00676
00677 static const char deldihed_doc[] =
00678 "Delete a dihedral angle between atoms with the given indices. If the\n"
00679 "dihedral does not exist, does nothing.\n\n"
00680 "Args:\n"
00681 " i (int): Index of first atom\n"
00682 " j (int): Index of second atom\n"
00683 " k (int): Index of third atom\n"
00684 " l (int): Index of fourth atom\n"
00685 " molid (int): Molecule ID to delete from. Defaults to top molecule.\n"
00686 "Returns:\n"
00687 " (bool) True if dihedral exists and was deleted";
00688 static PyObject* topo_del_dihed(PyObject *self, PyObject *args,
00689 PyObject *kwargs) {
00690 const char *kwlist[] = {"i", "j", "k", "l", "molid", NULL};
00691 PyObject *result = Py_False;
00692 int i, j, k, l, tmp, s;
00693 int molid = -1;
00694 Molecule *mol;
00695
00696 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii|i:topology.deldihedral",
00697 (char**) kwlist, &i, &j, &k, &l, &molid))
00698 return NULL;
00699
00700 VMDApp *app;
00701 if (!(app = get_vmdapp()))
00702 return NULL;
00703
00704 if (molid == -1)
00705 molid = app->molecule_top();
00706
00707 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00708 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00709 return NULL;
00710 }
00711
00712 if (i < 0 || j < 0 || k < 0 || l < 0 || k >= mol->nAtoms ||
00713 i >= mol->nAtoms || j >= mol->nAtoms || l >= mol->nAtoms) {
00714 PyErr_Format(PyExc_ValueError, "invalid dihedral atom indices %d-%d-%d-%d",
00715 i, j, k, l);
00716 return NULL;
00717 }
00718
00719
00720 if (i > l) {
00721 tmp = l;
00722 l = i;
00723 i = tmp;
00724 tmp = k;
00725 k = j;
00726 j = tmp;
00727 }
00728
00729 s = mol->num_dihedrals();
00730 for (tmp = 0; tmp < s; tmp++) {
00731 if (i == mol->dihedrals[4*tmp] && j == mol->dihedrals[4*tmp+1] \
00732 && k == mol->dihedrals[4*tmp+2] && l == mol->dihedrals[4*tmp+3]) {
00733
00734 mol->dihedrals[4*tmp] = mol->dihedrals[4*s-4];
00735 mol->dihedrals[4*tmp+1] = mol->dihedrals[4*s-3];
00736 mol->dihedrals[4*tmp+2] = mol->dihedrals[4*s-2];
00737 mol->dihedrals[4*tmp+3] = mol->dihedrals[4*s-1];
00738 if (mol->dihedralTypes.num() > tmp) {
00739 if (mol->dihedralTypes.num() == s)
00740 mol->dihedralTypes[tmp] = mol->dihedralTypes[s-1];
00741 else
00742 mol->dihedralTypes[tmp] = -1;
00743 }
00744 mol->dihedrals.pop();
00745 mol->dihedrals.pop();
00746 mol->dihedrals.pop();
00747 mol->dihedrals.pop();
00748 mol->set_dataset_flag(BaseMolecule::ANGLES);
00749
00750 result = Py_True;
00751 break;
00752 }
00753 }
00754
00755 Py_INCREF(result);
00756 return result;
00757 }
00758
00759
00760 static const char delimproper_doc[] =
00761 "Delete an improper dihedral angle between atoms with the given indices. If\n"
00762 "the improper does not exist, does nothing.\n\n"
00763 "Args:\n"
00764 " i (int): Index of first atom\n"
00765 " j (int): Index of second atom\n"
00766 " k (int): Index of third atom\n"
00767 " l (int): Index of fourth atom\n"
00768 " molid (int): Molecule ID to delete from. Defaults to top molecule.\n"
00769 "Returns:\n"
00770 " (bool) True if improper dihedral exists and was deleted";
00771 static PyObject* topo_del_improper(PyObject *self, PyObject *args,
00772 PyObject *kwargs) {
00773 const char *kwlist[] = {"i", "j", "k", "l", "molid", NULL};
00774 PyObject *result = Py_False;
00775 int i, j, k, l, tmp, s;
00776 int molid = -1;
00777 Molecule *mol;
00778
00779 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii|i:topology.delimproper",
00780 (char**) kwlist, &i, &j, &k, &l, &molid))
00781 return NULL;
00782
00783 VMDApp *app;
00784 if (!(app = get_vmdapp()))
00785 return NULL;
00786
00787 if (molid == -1)
00788 molid = app->molecule_top();
00789
00790 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00791 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00792 return NULL;
00793 }
00794
00795 if (i < 0 || j < 0 || k < 0 || l < 0 || k >= mol->nAtoms ||
00796 i >= mol->nAtoms || j >= mol->nAtoms || l >= mol->nAtoms) {
00797 PyErr_Format(PyExc_ValueError, "invalid imporper atom indices %d-%d-%d-%d",
00798 i, j, k, l);
00799 return NULL;
00800 }
00801
00802
00803 if (i > l) {
00804 tmp = l;
00805 l = i;
00806 i = tmp;
00807 tmp = k;
00808 k = j;
00809 j = tmp;
00810 }
00811
00812 s = mol->num_impropers();
00813 for (tmp = 0; tmp < s; tmp++) {
00814 if (i == mol->impropers[4*tmp ] && j == mol->impropers[4*tmp+1] &&
00815 k == mol->impropers[4*tmp+2] && l == mol->impropers[4*tmp+3]) {
00816
00817 mol->impropers[4*tmp ] = mol->impropers[4*s-4];
00818 mol->impropers[4*tmp+1] = mol->impropers[4*s-3];
00819 mol->impropers[4*tmp+2] = mol->impropers[4*s-2];
00820 mol->impropers[4*tmp+3] = mol->impropers[4*s-1];
00821
00822 if (mol->improperTypes.num() > tmp) {
00823 if (mol->improperTypes.num() == s)
00824 mol->improperTypes[tmp] = mol->improperTypes[s-1];
00825 else
00826 mol->improperTypes[tmp] = -1;
00827 }
00828 mol->impropers.pop();
00829 mol->impropers.pop();
00830 mol->impropers.pop();
00831 mol->impropers.pop();
00832 mol->set_dataset_flag(BaseMolecule::ANGLES);
00833
00834 result = Py_True;
00835 break;
00836 }
00837 }
00838
00839 Py_INCREF(result);
00840 return result;
00841 }
00842
00843
00844 static const char del_all_bond_doc[] =
00845 "Delete all bonds in a given molecule\n\n"
00846 "Args:\n"
00847 " molid (int): Molecule ID to delete bonds in. Defaults to top molecule.\n"
00848 "Returns:\n"
00849 " (int) Number of bonds deleted";
00850 static PyObject* topo_del_all_bonds(PyObject *self, PyObject *args,
00851 PyObject *kwargs) {
00852 const char *kwlist[] = {"molid", NULL};
00853 int molid = -1;
00854 Molecule *mol;
00855
00856 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.delallbonds",
00857 (char**) kwlist, &molid))
00858 return NULL;
00859
00860 VMDApp *app;
00861 if (!(app = get_vmdapp()))
00862 return NULL;
00863
00864 if (molid == -1)
00865 molid = app->molecule_top();
00866
00867 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00868 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00869 return NULL;
00870 }
00871
00872 int retval = mol->count_bonds();
00873 mol->clear_bonds();
00874
00875 return as_pyint(retval);
00876 }
00877
00878
00879 static const char del_all_angle_doc[] =
00880 "Delete all angles in a given molecule\n\n"
00881 "Args:\n"
00882 " molid (int): Molecule ID to delete angles in. Defaults to top molecule.\n"
00883 "Returns:\n"
00884 " (int) Number of angles deleted";
00885 static PyObject* topo_del_all_angles(PyObject *self, PyObject *args,
00886 PyObject *kwargs) {
00887 const char *kwlist[] = {"molid", NULL};
00888 int molid = -1;
00889 Molecule *mol;
00890
00891 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.delallangles",
00892 (char**) kwlist, &molid))
00893 return NULL;
00894
00895 VMDApp *app;
00896 if (!(app = get_vmdapp()))
00897 return NULL;
00898
00899 if (molid == -1)
00900 molid = app->molecule_top();
00901
00902 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00903 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00904 return NULL;
00905 }
00906
00907 int retval = mol->num_angles();
00908 mol->angles.clear();
00909 mol->angleTypes.clear();
00910
00911 return as_pyint(retval);
00912 }
00913
00914
00915 static const char del_all_dihed_doc[] =
00916 "Delete all dihedrals in a given molecule\n\n"
00917 "Args:\n"
00918 " molid (int): Molecule ID to delete in. Defaults to top molecule\n"
00919 "Returns:\n"
00920 " (int) Number of dihedrals deleted";
00921 static PyObject* topo_del_all_dihed(PyObject *self, PyObject *args,
00922 PyObject *kwargs) {
00923 const char *kwlist[] = {"molid", NULL};
00924 int molid = -1;
00925 Molecule *mol;
00926
00927 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.delalldihedrals",
00928 (char**) kwlist, &molid))
00929 return NULL;
00930
00931 VMDApp *app;
00932 if (!(app = get_vmdapp()))
00933 return NULL;
00934
00935 if (molid == -1)
00936 molid = app->molecule_top();
00937
00938 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00939 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00940 return NULL;
00941 }
00942
00943 int retval = mol->num_dihedrals();
00944 mol->dihedrals.clear();
00945 mol->dihedralTypes.clear();
00946
00947 return as_pyint(retval);
00948 }
00949
00950
00951 static const char del_all_improper_doc[] =
00952 "Delete all improper dihedrals in a given molecule\n\n"
00953 "Args:\n"
00954 " molid (int): Molecule ID to delete in. Defaults to top molecule\n"
00955 "Returns:\n"
00956 " (int) Number of impropers deleted";
00957 static PyObject* topo_del_all_impropers(PyObject *self, PyObject *args,
00958 PyObject *kwargs) {
00959 const char *kwlist[] = {"molid", NULL};
00960 int molid = -1;
00961 Molecule *mol;
00962
00963 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.delallimpropers",
00964 (char**) kwlist, &molid))
00965 return NULL;
00966
00967 VMDApp *app;
00968 if (!(app = get_vmdapp()))
00969 return NULL;
00970
00971 if (molid == -1)
00972 molid = app->molecule_top();
00973
00974 if (!(mol = app->moleculeList->mol_from_id(molid))) {
00975 PyErr_Format(PyExc_ValueError, "invalid molid '%d'", molid);
00976 return NULL;
00977 }
00978
00979 int retval = mol->num_impropers();
00980 mol->impropers.clear();
00981 mol->improperTypes.clear();
00982
00983 return as_pyint(retval);
00984 }
00985
00986
00987 static const char btypes_doc[] =
00988 "Get all bond types defined in the molecule. If molecule does not have\n"
00989 "bond types, will return an empty list.\n\n"
00990 "Args:\n"
00991 " molid (int): Molecule ID to query. Defaults to top molecule\n"
00992 "Returns:\n"
00993 " (list of str): Bond types in molecule";
00994 static PyObject* topo_bondtypes(PyObject *self, PyObject *args,
00995 PyObject *kwargs) {
00996 const char *kwlist[] = {"molid", NULL};
00997 PyObject *returnlist = NULL;
00998 int molid = -1;
00999 Molecule *mol;
01000 int i;
01001
01002 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.bondtypes",
01003 (char**) kwlist, &molid))
01004 return NULL;
01005
01006 VMDApp *app;
01007 if (!(app = get_vmdapp()))
01008 return NULL;
01009
01010 if (molid == -1)
01011 molid = app->molecule_top();
01012
01013 if (!(mol = app->moleculeList->mol_from_id(molid))) {
01014 PyErr_Format(PyExc_ValueError, "Invalid molecule id '%d'", molid);
01015 return NULL;
01016 }
01017
01018 if (!(returnlist = PyList_New(mol->bondTypeNames.num())))
01019 goto failure;
01020
01021 for (i = 0; i < mol->bondTypeNames.num(); i++) {
01022 PyList_SET_ITEM(returnlist, i, as_pystring(mol->bondTypeNames.name(i)));
01023 if (PyErr_Occurred())
01024 goto failure;
01025 }
01026
01027 return returnlist;
01028
01029 failure:
01030 PyErr_Format(PyExc_RuntimeError, "Problem building bond type list for molid "
01031 "%d", molid);
01032 Py_XDECREF(returnlist);
01033 return NULL;
01034 }
01035
01036
01037 static const char atypes_doc[] =
01038 "Get all angle types defined in the molecule. If molecule does not have angle\n"
01039 "types, will return an empty list.\n\n"
01040 "Args:\n"
01041 " molid (int): Molecule ID to query. Defaults to top molecule\n"
01042 "Returns:\n"
01043 " (list of str): Angle types in molecule";
01044 static PyObject* topo_angletypes(PyObject *self, PyObject *args,
01045 PyObject *kwargs) {
01046 const char *kwlist[] = {"molid", NULL};
01047 PyObject *returnlist = NULL;
01048 int molid = -1;
01049 Molecule *mol;
01050 int i;
01051
01052 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.angletypes",
01053 (char**) kwlist, &molid))
01054 return NULL;
01055
01056 VMDApp *app;
01057 if (!(app = get_vmdapp()))
01058 return NULL;
01059
01060 if (molid == -1)
01061 molid = app->molecule_top();
01062
01063 if (!(mol = app->moleculeList->mol_from_id(molid))) {
01064 PyErr_Format(PyExc_ValueError, "Invalid molecule id '%d'", molid);
01065 return NULL;
01066 }
01067
01068 if (!(returnlist = PyList_New(mol->angleTypeNames.num())))
01069 goto failure;
01070
01071 for (i = 0; i < mol->angleTypeNames.num(); i++) {
01072 PyList_SET_ITEM(returnlist, i, as_pystring(mol->angleTypeNames.name(i)));
01073 if (PyErr_Occurred())
01074 goto failure;
01075 }
01076
01077 return returnlist;
01078
01079 failure:
01080 PyErr_Format(PyExc_RuntimeError, "Problem building angle type list for molid "
01081 "%d", molid);
01082 Py_XDECREF(returnlist);
01083 return NULL;
01084 }
01085
01086
01087 static const char dtypes_doc[] =
01088 "Get all dihedral types defined in the molecule. If the molecule does not\n"
01089 "have dihedral types, will return an empty list.\n\n"
01090 "Args:\n"
01091 " molid (int): Molecule ID to query. Defaults to top molecule\n"
01092 "Returns:\n"
01093 " (list of str): Dihedral types in molecule";
01094 static PyObject* topo_dihetypes(PyObject *self, PyObject *args,
01095 PyObject *kwargs) {
01096 const char *kwlist[] = {"molid", NULL};
01097 PyObject *returnlist = NULL;
01098 int molid = -1;
01099 Molecule *mol;
01100 int i;
01101
01102 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.dihedraltypes",
01103 (char**) kwlist, &molid))
01104 return NULL;
01105
01106 VMDApp *app;
01107 if (!(app = get_vmdapp()))
01108 return NULL;
01109
01110 if (molid == -1)
01111 molid = app->molecule_top();
01112
01113 if (!(mol = app->moleculeList->mol_from_id(molid))) {
01114 PyErr_Format(PyExc_ValueError, "Invalid molecule id '%d'", molid);
01115 return NULL;
01116 }
01117
01118 if (!(returnlist = PyList_New(mol->dihedralTypeNames.num())))
01119 goto failure;
01120
01121 for (i = 0; i < mol->dihedralTypeNames.num(); i++) {
01122 PyList_SET_ITEM(returnlist, i, as_pystring(mol->dihedralTypeNames.name(i)));
01123 if (PyErr_Occurred())
01124 goto failure;
01125 }
01126
01127 return returnlist;
01128
01129 failure:
01130 PyErr_Format(PyExc_RuntimeError, "Problem building dihedral type list for "
01131 "molid %d", molid);
01132 Py_XDECREF(returnlist);
01133 return NULL;
01134 }
01135
01136
01137 static const char itypes_doc[] =
01138 "Get all improper dihedral types defined in the molecule. If the molecule\n"
01139 "not have improper types, will return an empty list.\n\n"
01140 "Args:\n"
01141 " molid (int): Molecule ID to query. Defaults to top molecule\n"
01142 "Returns:\n"
01143 " (list of str): Improper dihedral types in molecule";
01144 static PyObject* topo_imptypes(PyObject *self, PyObject *args, PyObject *kwargs) {
01145 const char *kwlist[] = {"molid", NULL};
01146 PyObject *returnlist = NULL;
01147 int molid = -1;
01148 Molecule *mol;
01149 int i;
01150
01151 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:topology.impropertypes",
01152 (char**) kwlist, &molid))
01153 return NULL;
01154
01155 VMDApp *app;
01156 if (!(app = get_vmdapp()))
01157 return NULL;
01158
01159 if (molid == -1)
01160 molid = app->molecule_top();
01161
01162 if (!(mol = app->moleculeList->mol_from_id(molid))) {
01163 PyErr_Format(PyExc_ValueError, "Invalid molecule id '%d'", molid);
01164 return NULL;
01165 }
01166
01167 if (!(returnlist = PyList_New(mol->improperTypeNames.num())))
01168 goto failure;
01169
01170 for (i = 0; i < mol->improperTypeNames.num(); i++) {
01171 PyList_SET_ITEM(returnlist, i, as_pystring(mol->improperTypeNames.name(i)));
01172 if (PyErr_Occurred())
01173 goto failure;
01174 }
01175
01176 return returnlist;
01177
01178 failure:
01179 PyErr_Format(PyExc_RuntimeError, "Problem building improper dihedral type "
01180 "list for molid %d", molid);
01181 Py_XDECREF(returnlist);
01182 return NULL;
01183 }
01184
01185
01186 static PyMethodDef methods[] = {
01187 {"bonds", (PyCFunction)topo_get_bond, METH_VARARGS | METH_KEYWORDS, bond_doc},
01188 {"angles", (PyCFunction)topo_get_angle, METH_VARARGS | METH_KEYWORDS, angle_doc},
01189 {"dihedrals", (PyCFunction)topo_get_dihed, METH_VARARGS | METH_KEYWORDS, dihed_doc},
01190 {"impropers", (PyCFunction)topo_get_impro, METH_VARARGS | METH_KEYWORDS, impropers_doc},
01191 {"addbond", (PyCFunction)topo_add_bond, METH_VARARGS | METH_KEYWORDS, addbond_doc},
01192 {"addangle", (PyCFunction)topo_add_angle, METH_VARARGS | METH_KEYWORDS, addangle_doc},
01193 {"adddihedral", (PyCFunction)topo_add_dihed, METH_VARARGS | METH_KEYWORDS, adddihed_doc},
01194 {"addimproper", (PyCFunction)topo_add_improp, METH_VARARGS | METH_KEYWORDS, addimproper_doc},
01195 {"delbond", (PyCFunction)topo_del_bond, METH_VARARGS | METH_KEYWORDS, delbond_doc},
01196 {"delangle", (PyCFunction)topo_del_angle, METH_VARARGS | METH_KEYWORDS, delangle_doc},
01197 {"deldihedral", (PyCFunction)topo_del_dihed, METH_VARARGS | METH_KEYWORDS, deldihed_doc},
01198 {"delimproper", (PyCFunction)topo_del_improper, METH_VARARGS | METH_KEYWORDS, delimproper_doc},
01199 {"delallbonds", (PyCFunction)topo_del_all_bonds, METH_VARARGS | METH_KEYWORDS, del_all_bond_doc},
01200 {"delallangles", (PyCFunction)topo_del_all_angles, METH_VARARGS | METH_KEYWORDS, del_all_angle_doc},
01201 {"delalldihedrals", (PyCFunction)topo_del_all_dihed, METH_VARARGS | METH_KEYWORDS, del_all_dihed_doc},
01202 {"delallimpropers", (PyCFunction)topo_del_all_impropers, METH_VARARGS | METH_KEYWORDS, del_all_improper_doc},
01203 {"bondtypes", (PyCFunction)topo_bondtypes, METH_VARARGS | METH_KEYWORDS, btypes_doc},
01204 {"angletypes", (PyCFunction)topo_angletypes, METH_VARARGS | METH_KEYWORDS, atypes_doc},
01205 {"dihedraltypes", (PyCFunction)topo_dihetypes, METH_VARARGS | METH_KEYWORDS, dtypes_doc},
01206 {"impropertypes", (PyCFunction)topo_imptypes, METH_VARARGS | METH_KEYWORDS, itypes_doc},
01207 {NULL, NULL}
01208 };
01209
01210
01211 static const char topo_moddoc[] =
01212 "Methods for querying or modifying the topology of a molecule, which consists "
01213 "of all defined bonds, angles, dihedrals, and impropers, for applicable "
01214 "topology file formats.";
01215
01216
01217 #if PY_MAJOR_VERSION >= 3
01218 static struct PyModuleDef topologydef = {
01219 PyModuleDef_HEAD_INIT,
01220 "topology",
01221 topo_moddoc,
01222 -1,
01223 methods,
01224 };
01225 #endif
01226
01227
01228 PyObject* inittopology(void) {
01229 #if PY_MAJOR_VERSION >= 3
01230 PyObject *m = PyModule_Create(&topologydef);
01231 #else
01232 PyObject *m = Py_InitModule3("topology", methods, topo_moddoc);
01233 #endif
01234
01235 return m;
01236 }
01237
01238