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
00023 #ifdef VMDIMD
00024
00025 #include "CmdIMD.h"
00026 #include "CommandQueue.h"
00027 #include "VMDApp.h"
00028 #include "MoleculeList.h"
00029 #include "IMDMgr.h"
00030
00031 static const char connect_doc[] =
00032 "Connect to an IMD server\n\n"
00033 "Args:\n"
00034 " host (str): Server hostname\n"
00035 " port (int): Port running IMD server";
00036 static PyObject* py_imdconnect(PyObject *self, PyObject *args, PyObject *kwargs) {
00037 const char *kwlist[] = {"host", "port", NULL};
00038 char *host;
00039 int port;
00040
00041 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si:imd.connect",
00042 (char**) kwlist, &host, &port))
00043 return NULL;
00044
00045 VMDApp *app;
00046 if (!(app = get_vmdapp()))
00047 return NULL;
00048
00049 Molecule *mol = app->moleculeList->top();
00050 if (!mol) {
00051 PyErr_SetString(PyExc_ValueError, "No molecule loaded");
00052 return NULL;
00053 }
00054
00055 if (app->imdMgr->connected()) {
00056 PyErr_SetString(PyExc_ValueError, "Can't create new IMD connection: "
00057 "already connected.");
00058 return NULL;
00059 }
00060
00061 if (!app->imd_connect(mol->id(), host, port)) {
00062 PyErr_Format(PyExc_RuntimeError, "Unable to connect to IMD server '%s:%d'",
00063 host, port);
00064 return NULL;
00065 }
00066
00067 Py_INCREF(Py_None);
00068 return Py_None;
00069 }
00070
00071
00072 static const char pause_doc[] =
00073 "Pause a running IMD simulation";
00074 static PyObject* py_imdpause(PyObject *self, PyObject *args) {
00075 VMDApp *app;
00076 if (!(app = get_vmdapp()))
00077 return NULL;
00078
00079 if (!app->imdMgr->connected()) {
00080 PyErr_SetString(PyExc_ValueError, "Not connected to an IMD server");
00081 return NULL;
00082 }
00083
00084 app->imdMgr->togglepause();
00085 app->commandQueue->runcommand(new CmdIMDSim(CmdIMDSim::PAUSE_TOGGLE));
00086
00087 Py_INCREF(Py_None);
00088 return Py_None;
00089 }
00090
00091
00092 static const char detach_doc[] =
00093 "Detach from a running IMD simulation";
00094 static PyObject *py_imddetach(PyObject *self, PyObject *args) {
00095 VMDApp *app;
00096 if (!(app = get_vmdapp()))
00097 return NULL;
00098
00099 if (!app->imdMgr->connected()) {
00100 PyErr_SetString(PyExc_ValueError, "Not connected to an IMD server");
00101 return NULL;
00102 }
00103
00104 app->imdMgr->detach();
00105 app->commandQueue->runcommand(new CmdIMDSim(CmdIMDSim::DETACH));
00106
00107 Py_INCREF(Py_None);
00108 return Py_None;
00109 }
00110
00111
00112 static const char kill_doc[] =
00113 "Halt a running IMD simulation. Also detaches.";
00114 static PyObject* py_imdkill(PyObject *self, PyObject *args) {
00115 VMDApp *app;
00116 if (!(app = get_vmdapp()))
00117 return NULL;
00118
00119 if (!app->imdMgr->connected()) {
00120 PyErr_SetString(PyExc_ValueError, "Not connected to an IMD server");
00121 return NULL;
00122 }
00123
00124 app->imdMgr->kill();
00125 app->commandQueue->runcommand(new CmdIMDSim(CmdIMDSim::KILL));
00126
00127 Py_INCREF(Py_None);
00128 return Py_None;
00129 }
00130
00131
00132 static const char transfer_doc[] =
00133 "Get and/or set how often timesteps are sent to the IMD server\n\n"
00134 "Args:\n"
00135 " rate (int): New transfer rate, or None to query. Rate must be greater\n"
00136 " than 0\n"
00137 "Returns:\n"
00138 " (int): Updated transfer rate";
00139 static PyObject* py_imdtransfer(PyObject *self, PyObject *args,
00140 PyObject *kwargs) {
00141 const char *kwlist[] = {"rate", NULL};
00142 PyObject *rateobj = NULL;
00143 int rate;
00144
00145 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:imd.transfer",
00146 (char**) kwlist, &rateobj))
00147 return NULL;
00148
00149 VMDApp *app;
00150 if (!(app = get_vmdapp()))
00151 return NULL;
00152
00153 if (rateobj) {
00154 rate = as_int(rateobj);
00155
00156 if (rate <= 0) {
00157 PyErr_SetString(PyExc_ValueError, "transfer rate must be > 0");
00158 return NULL;
00159 }
00160
00161 app->imdMgr->set_trans_rate(rate);
00162 app->commandQueue->runcommand(new CmdIMDRate(CmdIMDRate::TRANSFER, rate));
00163 }
00164
00165 return as_pyint(app->imdMgr->get_trans_rate());
00166 }
00167
00168
00169 static const char keep_doc[] =
00170 "Get and/or set how often timesteps are saved.\n\n"
00171 "Args:\n"
00172 " rate (int): Save frequency, or None to query. Rate must be greater than\n"
00173 " or equal to 0\n"
00174 "Returns:\n"
00175 " (int): Updated save frequency";
00176 static PyObject* py_imdkeep(PyObject *self, PyObject *args, PyObject *kwargs) {
00177 const char *kwlist[] = {"rate", NULL};
00178 PyObject *rateobj = NULL;
00179 int rate;
00180
00181 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:imd.keep",
00182 (char**) kwlist, &rateobj))
00183 return NULL;
00184
00185 VMDApp *app;
00186 if (!(app = get_vmdapp()))
00187 return NULL;
00188
00189 if (rateobj) {
00190 rate = as_int(rateobj);
00191
00192 if (rate < 0) {
00193 PyErr_SetString(PyExc_ValueError, "keep value must be >= 0");
00194 return NULL;
00195 }
00196
00197 app->imdMgr->set_keep_rate(rate);
00198 app->commandQueue->runcommand(new CmdIMDRate(CmdIMDRate::KEEP, rate));
00199 }
00200
00201 return as_pyint(app->imdMgr->get_keep_rate());
00202 }
00203
00204
00205 static const char copy_doc[] =
00206 "Set if unit cell information should be copied from previous frame\n\n"
00207 "Args:\n"
00208 " copy (bool): If cell information should be copied";
00209 static PyObject* py_copyunitcell(PyObject *self, PyObject *args,
00210 PyObject *kwargs) {
00211 const char *kwlist[] = {"copy", NULL};
00212 CmdIMDCopyUnitCell::CmdIMDCopyUnitCellCommand c;
00213 int copy;
00214
00215 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:imd.copyunitcell",
00216 (char**) kwlist, convert_bool, ©))
00217 return NULL;
00218
00219 VMDApp *app;
00220 if (!(app = get_vmdapp()))
00221 return NULL;
00222
00223 app->imdMgr->set_copyunitcell(copy);
00224 c = copy ? CmdIMDCopyUnitCell::COPYCELL_ON : CmdIMDCopyUnitCell::COPYCELL_OFF;
00225 app->commandQueue->runcommand(new CmdIMDCopyUnitCell(c));
00226
00227 Py_INCREF(Py_None);
00228 return Py_None;
00229 }
00230
00231
00232 static const char connected_doc[] =
00233 "Query if an IMD connection exists\n\n"
00234 "Returns:\n"
00235 " (bool): True if a connection exists, False otherwise";
00236 static PyObject* py_imdconnected(PyObject *self, PyObject *args) {
00237 VMDApp *app;
00238 if (!(app = get_vmdapp()))
00239 return NULL;
00240
00241 PyObject *result = app->imdMgr->connected() ? Py_True : Py_False;
00242 Py_INCREF(result);
00243 return result;
00244 }
00245
00246 static const char sendforces_doc[] =
00247 "Send forces to connected MD engine\n\n"
00248 "Args:\n"
00249 " indices (list of ints): Atomic indices to which forces will be applied\n"
00250 " forces (flat nx3 list): forces that will be applied to the individual atoms\n";
00251 static PyObject* py_sendforces(PyObject *self, PyObject *args,
00252 PyObject *kwargs) {
00253 VMDApp *app;
00254 if (!(app = get_vmdapp()))
00255 return NULL;
00256 if (! app->imdMgr->connected()) {
00257 PyErr_SetString(PyExc_ValueError, "Not connected to an IMD server");
00258 return NULL;
00259 }
00260 const char *kwlist[] = {"indices", "forces", NULL};
00261 PyObject *idxs, *idxseq;
00262 PyObject *forces, *forceseq;
00263 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:imd.sendforces",
00264 (char**) kwlist, &idxs, &forces))
00265 return NULL;
00266 int n;
00267 if (!(idxseq = PySequence_Fast(idxs, "indices must be a python sequence"))) {
00268 Py_XDECREF(idxseq);
00269 return NULL;
00270 }
00271 if (!(forceseq = PySequence_Fast(forces, "forces must be a python sequence"))) {
00272 Py_XDECREF(idxseq);
00273 Py_XDECREF(forceseq);
00274 return NULL;
00275 }
00276 n = PySequence_Fast_GET_SIZE(idxseq);
00277 if (PySequence_Fast_GET_SIZE(forceseq) != 3 * n) {
00278 Py_XDECREF(idxseq);
00279 Py_XDECREF(forceseq);
00280 PyErr_SetString(PyExc_ValueError, "The force list passed is not 3 times as long as the index list.");
00281 return NULL;
00282 }
00283 int *cidxs = new int[n];
00284 float *cforces = new float[3*n];
00285 for (int i = 0; i < n; i++) {
00286 int result = (int) PyLong_AsLong(PySequence_Fast_GET_ITEM(idxseq,i));
00287 if (result < 0) {
00288 Py_XDECREF(idxseq);
00289 Py_XDECREF(forceseq);
00290 PyErr_SetString(PyExc_ValueError, "A value in the index list is not a positive integer");
00291 return NULL;
00292 }
00293 cidxs[i] = result;
00294 }
00295 for (int i = 0; i < 3*n; i++) {
00296 cforces[i] = (float) PyFloat_AS_DOUBLE(PySequence_Fast_GET_ITEM(forceseq,i));
00297 }
00298 app->imd_sendforces(n, cidxs, cforces);
00299 delete cidxs;
00300 delete cforces;
00301 Py_XDECREF(idxseq);
00302 Py_XDECREF(forceseq);
00303 Py_INCREF(Py_None);
00304 return Py_None;
00305 }
00306
00307 static PyMethodDef methods[] = {
00308 {"connected", (PyCFunction)py_imdconnected, METH_NOARGS, connected_doc},
00309 {"connect", (PyCFunction)py_imdconnect, METH_VARARGS | METH_KEYWORDS, connect_doc},
00310 {"pause", (PyCFunction)py_imdpause, METH_NOARGS, pause_doc},
00311 {"detach", (PyCFunction)py_imddetach, METH_NOARGS, detach_doc},
00312 {"kill", (PyCFunction)py_imdkill, METH_NOARGS, kill_doc},
00313 {"transfer", (PyCFunction)py_imdtransfer, METH_VARARGS | METH_KEYWORDS, transfer_doc},
00314 {"keep", (PyCFunction)py_imdkeep, METH_VARARGS | METH_KEYWORDS, keep_doc},
00315 {"copyunitcell", (PyCFunction)py_copyunitcell, METH_VARARGS | METH_KEYWORDS, copy_doc},
00316 {"sendforces", (PyCFunction)py_sendforces, METH_VARARGS | METH_KEYWORDS, sendforces_doc},
00317 {NULL, NULL}
00318 };
00319
00320
00321 static const char imd_moddoc[] =
00322 "Methods for controlling interactive molecular dynamics simulations";
00323
00324
00325 #if PY_MAJOR_VERSION >= 3
00326 static struct PyModuleDef imddef = {
00327 PyModuleDef_HEAD_INIT,
00328 "imd",
00329 imd_moddoc,
00330 -1,
00331 methods,
00332 };
00333 #endif
00334
00335
00336 PyObject* initimd() {
00337 #if PY_MAJOR_VERSION >= 3
00338 PyObject *m = PyModule_Create(&imddef);
00339 #else
00340 PyObject *m = Py_InitModule3("imd", methods, imd_moddoc);
00341 #endif
00342 return m;
00343 }
00344
00345 #endif
00346