fixed warnings in gmx_gpu_utils and openmm_wrapper
[gromacs/rigid-bodies.git] / src / kernel / openmm_wrapper.cpp
blobda54119227b890d91fe2ddce4edeac1451fad845
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2010, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
37 * Note, that parts of this source code originate from the Simtk release
38 * of OpenMM accelerated Gromacs, for more details see:
39 * https://simtk.org/project/xml/downloads.xml?group_id=161#package_id600
42 #include <cmath>
43 #include <set>
44 #include <iostream>
45 #include <sstream>
46 #include <fstream>
47 #include <map>
48 #include <vector>
49 #include <cctype>
50 #include <algorithm>
52 using namespace std;
54 #include "OpenMM.h"
56 #include "gmx_fatal.h"
57 #include "typedefs.h"
58 #include "mdrun.h"
59 #include "physics.h"
60 #include "string2.h"
61 #include "gmx_gpu_utils.h"
62 #include "mtop_util.h"
64 #include "openmm_wrapper.h"
66 using namespace OpenMM;
68 /*! \cond */
69 #define MEM_ERR_MSG(str) \
70 "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
71 "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
72 "overclocked and that the device is properly cooled.\n", (str)
73 /*! \endcond */
75 #define COMBRULE_CHK_TOL 1e-6
76 #define COMBRULE_SIGMA(sig1, sig2) (((sig1) + (sig2))/2)
77 #define COMBRULE_EPS(eps1, eps2) (sqrt((eps1) * (eps2)))
79 /*!
80 * \brief Convert string to integer type.
81 * \param[in] s String to convert from.
82 * \param[in] f Basefield format flag that takes any of the following I/O
83 * manipulators: dec, hex, oct.
84 * \param[out] t Destination variable to convert to.
86 template <class T>
87 static bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
89 istringstream iss(s);
90 return !(iss >> f >> t).fail();
93 /*!
94 * \brief Split string around a given delimiter.
95 * \param[in] s String to split.
96 * \param[in] delim Delimiter character.
97 * \returns Vector of strings found in \p s.
99 static vector<string> split(const string &s, char delim)
101 vector<string> elems;
102 stringstream ss(s);
103 string item;
104 while (getline(ss, item, delim))
106 if (item.length() != 0)
107 elems.push_back(item);
109 return elems;
113 * \brief Split a string of the form "option=value" into "option" and "value" strings.
114 * This string corresponds to one option and the associated value from the option list
115 * in the mdrun -device argument.
117 * \param[in] s A string containing an "option=value" pair that needs to be split up.
118 * \param[out] opt The name of the option.
119 * \param[out] val Value of the option.
121 static void splitOptionValue(const string &s, string &opt, string &val)
123 size_t eqPos = s.find('=');
124 if (eqPos != string::npos)
126 opt = s.substr(0, eqPos);
127 if (eqPos != s.length()) val = s.substr(eqPos+1);
132 * \brief Compare two strings ignoring case.
133 * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
134 * \param[in] s1 String.
135 * \param[in] s2 String.
136 * \returns Similarly to the C function strncasecmp(), the return value is an
137 integer less than, equal to, or greater than 0 if \p s1 less than,
138 identical to, or greater than \p s2.
140 static bool isStringEqNCase(const string s1, const string s2)
142 return (gmx_strncasecmp(s1.c_str(), s2.c_str(), max(s1.length(), s2.length())) == 0);
146 * \brief Convert string to upper case.
148 * \param[in] s String to convert to uppercase.
149 * \returns The given string converted to uppercase.
151 static string toUpper(const string &s)
153 string stmp(s);
154 std::transform(stmp.begin(), stmp.end(), stmp.begin(), static_cast < int(*)(int) > (toupper));
155 return stmp;
158 /*!
159 \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms,
160 GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
161 GmxOpenMMPlatformOptions#force_dev. */
162 /* {@ */
163 #define SIZEOF_PLATFORMS 1 // 2
164 #define SIZEOF_MEMTESTS 3
165 #define SIZEOF_DEVICEIDS 1
166 #define SIZEOF_FORCE_DEV 2
168 #define SIZEOF_CHECK_COMBRULE 2
169 /* @} */
171 /*! Possible platform options in the mdrun -device option. */
172 static const char *devOptStrings[] = { "platform", "deviceid", "memtest", "force-device", "check-combrule" };
174 /*! Enumerated platform options in the mdrun -device option. */
175 enum devOpt
177 PLATFORM = 0,
178 DEVICEID = 1,
179 MEMTEST = 2,
180 FORCE_DEVICE = 3
184 * \brief Class to extract and manage the platform options in the mdrun -device option.
187 class GmxOpenMMPlatformOptions
189 public:
190 GmxOpenMMPlatformOptions(const char *opt);
191 ~GmxOpenMMPlatformOptions() { options.clear(); }
192 string getOptionValue(const string &opt);
193 void remOption(const string &opt);
194 void print();
195 private:
196 void setOption(const string &opt, const string &val);
198 map<string, string> options; /*!< Data structure to store the option (name, value) pairs. */
200 static const char * const platforms[SIZEOF_PLATFORMS]; /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
201 static const char * const memtests[SIZEOF_MEMTESTS]; /*!< Available types of memory tests, also valid
202 any positive integer >=15; size #SIZEOF_MEMTESTS */
203 static const char * const deviceid[SIZEOF_DEVICEIDS]; /*!< Possible values for deviceid option;
204 also valid any positive integer; size #SIZEOF_DEVICEIDS */
205 static const char * const force_dev[SIZEOF_FORCE_DEV]; /*!< Possible values for for force-device option;
206 size #SIZEOF_FORCE_DEV */
207 static const char * const check_combrule[SIZEOF_CHECK_COMBRULE]; /* XXX temporary debug feature to
208 turn off combination rule check */
211 const char * const GmxOpenMMPlatformOptions::platforms[SIZEOF_PLATFORMS]
212 = {"CUDA"};
213 //= { "Reference", "CUDA" /*,"OpenCL"*/ };
214 const char * const GmxOpenMMPlatformOptions::memtests[SIZEOF_MEMTESTS]
215 = { "15", "full", "off" };
216 const char * const GmxOpenMMPlatformOptions::deviceid[SIZEOF_DEVICEIDS]
217 = { "0" };
218 const char * const GmxOpenMMPlatformOptions::force_dev[SIZEOF_FORCE_DEV]
219 = { "no", "yes" };
220 const char * const GmxOpenMMPlatformOptions::check_combrule[SIZEOF_CHECK_COMBRULE]
221 = { "yes", "no" };
224 * \brief Contructor.
225 * Takes the option list, parses it, checks the options and their values for validity.
226 * When certain options are not provided by the user, as default value the first item
227 * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms,
228 * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
229 * GmxOpenMMPlatformOptions#force_dev).
230 * \param[in] optionString Option list part of the mdrun -device parameter.
232 GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString)
234 // set default values
235 setOption("platform", platforms[0]);
236 setOption("memtest", memtests[0]);
237 setOption("deviceid", deviceid[0]);
238 setOption("force-device", force_dev[0]);
239 setOption("check-combrule", check_combrule[0]);
241 string opt(optionString);
243 // remove all whitespaces
244 opt.erase(remove_if(opt.begin(), opt.end(), ::isspace), opt.end());
245 // tokenize around ","-s
246 vector<string> tokens = split(opt, ',');
248 for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
250 string opt = "", val = "";
251 splitOptionValue(*it, opt, val);
253 if (isStringEqNCase(opt, "platform"))
255 /* no check, this will fail if platform does not exist when we try to set it */
256 setOption(opt, val);
257 continue;
260 if (isStringEqNCase(opt, "memtest"))
262 /* the value has to be an integer >15(s) or "full" OR "off" */
263 if (!isStringEqNCase(val, "full") && !isStringEqNCase(val, "off"))
265 int secs;
266 if (!from_string<int>(secs, val, std::dec))
268 gmx_fatal(FARGS, "Invalid value for option memtest option: \"%s\"!", val.c_str());
270 if (secs < 15)
272 gmx_fatal(FARGS, "Incorrect value for memtest option (%d). "
273 "Memtest needs to run for at least 15s!", secs);
276 setOption(opt, val);
277 continue;
280 if (isStringEqNCase(opt, "deviceid"))
282 int id;
283 if (!from_string<int>(id, val, std::dec) )
285 gmx_fatal(FARGS, "Invalid device id: \"%s\"!", val.c_str());
287 setOption(opt, val);
288 continue;
291 if (isStringEqNCase(opt, "force-device"))
293 /* */
294 if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
296 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
298 setOption(opt, val);
299 continue;
302 if (isStringEqNCase(opt, "check-combrule"))
304 /* */
305 if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
307 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
309 setOption(opt, val);
310 continue;
314 // if we got till here something went wrong
315 gmx_fatal(FARGS, "Invalid OpenMM platform option: \"%s\"!", (*it).c_str());
321 * \brief Getter function.
322 * \param[in] opt Name of the option.
323 * \returns Returns the value associated to an option.
325 string GmxOpenMMPlatformOptions::getOptionValue(const string &opt)
327 map<string, string> :: const_iterator it = options.find(toUpper(opt));
328 if (it != options.end())
330 return it->second;
332 else
334 return NULL;
339 * \brief Setter function - private, only used from contructor.
340 * \param[in] opt Name of the option.
341 * \param[in] val Value for the option.
343 void GmxOpenMMPlatformOptions::setOption(const string &opt, const string &val)
345 options[toUpper(opt)] = val;
349 * \brief Removes an option with its value from the map structure. If the option
350 * does not exist, returns without any action.
351 * \param[in] opt Name of the option.
353 void GmxOpenMMPlatformOptions::remOption(const string &opt)
355 options.erase(toUpper(opt));
359 * \brief Print option-value pairs to a file (debugging function).
361 void GmxOpenMMPlatformOptions::print()
363 cout << ">> Platform options: " << endl
364 << ">> platform = " << getOptionValue("platform") << endl
365 << ">> deviceID = " << getOptionValue("deviceid") << endl
366 << ">> memtest = " << getOptionValue("memtest") << endl
367 << ">> force-device = " << getOptionValue("force-device") << endl;
371 * \brief Container for OpenMM related data structures that represent the bridge
372 * between the Gromacs data-structures and the OpenMM library and is but it's
373 * only passed through the API functions as void to disable direct access.
375 class OpenMMData
377 public:
378 System* system; /*! The system to simulate. */
379 Context* context; /*! The OpenMM context in which the simulation is carried out. */
380 Integrator* integrator; /*! The integrator used in the simulation. */
381 bool removeCM; /*! If \true remove venter of motion, false otherwise. */
382 GmxOpenMMPlatformOptions *platformOpt; /*! Platform options. */
386 * \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
387 * \param[in] fplog Pointer to gromacs log file.
388 * \param[in] devId Device id of the GPU to run the test on.
389 Note: as OpenMM previously creates the context,for now this is always -1.
390 * \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in
391 * stdout messages/log between memtest carried out before and after simulation.
392 * \param[in] opt Pointer to platform options object.
394 static void runMemtest(FILE* fplog, int devId, const char* pre_post, GmxOpenMMPlatformOptions *opt)
396 char strout_buf[STRLEN];
397 int which_test;
398 int res = 0;
399 string s = opt->getOptionValue("memtest");
400 const char *test_type = s.c_str();
402 if (!gmx_strcasecmp(test_type, "off"))
404 which_test = 0;
406 else
408 if (!gmx_strcasecmp(test_type, "full"))
410 which_test = 2;
412 else
414 from_string<int>(which_test, test_type, std::dec);
418 if (which_test < 0)
420 gmx_fatal(FARGS, "Amount of seconds for memetest is negative (%d). ", which_test);
423 switch (which_test)
425 case 0: /* no memtest */
426 sprintf(strout_buf, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
427 "incorrect results!", pre_post);
428 fprintf(fplog, "%s\n", strout_buf);
429 gmx_warning(strout_buf);
430 break; /* case 0 */
432 case 1: /* quick memtest */
433 fprintf(fplog, "%s-simulation %s GPU memtest in progress...\n", pre_post, test_type);
434 fprintf(stdout, "\n%s-simulation %s GPU memtest in progress...", pre_post, test_type);
435 fflush(fplog);
436 fflush(stdout);
437 res = do_quick_memtest(devId);
438 break; /* case 1 */
440 case 2: /* full memtest */
441 fprintf(fplog, "%s-simulation %s memtest in progress...\n", pre_post, test_type);
442 fprintf(stdout, "\n%s-simulation %s memtest in progress...", pre_post, test_type);
443 fflush(fplog);
444 fflush(stdout);
445 res = do_full_memtest(devId);
446 break; /* case 2 */
448 default: /* timed memtest */
449 fprintf(fplog, "%s-simulation ~%ds memtest in progress...\n", pre_post, which_test);
450 fprintf(stdout, "\n%s-simulation ~%ds memtest in progress...", pre_post, which_test);
451 fflush(fplog);
452 fflush(stdout);
453 res = do_timed_memtest(devId, which_test);
456 if (which_test != 0)
458 if (res != 0)
460 gmx_fatal(FARGS, MEM_ERR_MSG(pre_post));
462 else
464 fprintf(fplog, "Memory test completed without errors.\n");
465 fflush(fplog);
466 fprintf(stdout, "done, no errors detected\n");
467 fflush(stdout);
473 * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
475 * \param[in] c12
476 * \param[in] c6
477 * \param[out] sigma
478 * \param[out] epsilon
480 static void convert_c_12_6(double c12, double c6, double *sigma, double *epsilon)
482 if (c12 == 0 && c6 == 0)
484 *epsilon = 0.0;
485 *sigma = 1.0;
487 else if (c12 > 0 && c6 > 0)
489 *epsilon = (c6*c6)/(4.0*c12);
490 *sigma = pow(c12/c6, 1.0/6.0);
492 else
494 gmx_fatal(FARGS,"OpenMM only supports c6 > 0 and c12 > 0 or c6 = c12 = 0.");
499 * \brief Does gromacs option checking.
501 * Checks the gromacs mdp options for features unsupported in OpenMM, case in which
502 * interrupts the execution. It also warns the user about pecularities of OpenMM
503 * implementations.
504 * \param[in] fplog Gromacs log file pointer.
505 * \param[in] ir Gromacs input parameters, see ::t_inputrec
506 * \param[in] top Gromacs node local topology, \see gmx_localtop_t
507 * \param[in] state Gromacs state structure \see ::t_state
508 * \param[in] mdatoms Gromacs atom parameters, \see ::t_mdatoms
509 * \param[in] fr \see ::t_forcerec
510 * \param[in] state Gromacs systems state, \see ::t_state
512 static void checkGmxOptions(FILE* fplog, GmxOpenMMPlatformOptions *opt,
513 t_inputrec *ir, gmx_localtop_t *top,
514 t_forcerec *fr, t_state *state)
516 char warn_buf[STRLEN];
517 int i, j, natoms;
518 double c6, c12;
519 double sigma_ij=0, sigma_ji=0, sigma_ii=0, sigma_jj=0, sigma_comb;
520 double eps_ij=0, eps_ji=0, eps_ii=0, eps_jj=0, eps_comb;
522 /* Abort if unsupported critical options are present */
524 /* Integrator */
525 if (ir->eI == eiMD)
527 gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
530 if ( (ir->eI != eiMD) &&
531 (ir->eI != eiVV) &&
532 (ir->eI != eiVVAK) &&
533 (ir->eI != eiSD1) &&
534 (ir->eI != eiSD2) &&
535 (ir->eI != eiBD) )
537 gmx_fatal(FARGS, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
540 /* Electroctstics */
541 if ( (ir->coulombtype != eelPME) &&
542 (ir->coulombtype != eelRF) &&
543 (ir->coulombtype != eelEWALD) &&
544 // no-cutoff
545 ( !(ir->coulombtype == eelCUT && ir->rcoulomb == 0 && ir->rvdw == 0)) )
547 gmx_fatal(FARGS,"OpenMM supports only the following methods for electrostatics: "
548 "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
551 if (ir->etc != etcNO &&
552 ir->eI != eiSD1 &&
553 ir->eI != eiSD2 &&
554 ir->eI != eiBD )
556 gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
559 if (ir->implicit_solvent == eisGBSA &&
560 ir->gb_algorithm != egbOBC )
562 gmx_warning("OpenMM does not support the specified algorithm for Generalized Born, will use OBC instead.");
565 if (ir->opts.ngtc > 1)
566 gmx_fatal(FARGS,"OpenMM does not support multiple temperature coupling groups.");
568 if (ir->epc != etcNO)
569 gmx_fatal(FARGS,"OpenMM does not support pressure coupling.");
571 if (ir->opts.annealing[0])
572 gmx_fatal(FARGS,"OpenMM does not support simulated annealing.");
574 if (top->idef.il[F_CONSTR].nr > 0 && ir->eConstrAlg != econtSHAKE)
575 gmx_warning("OpenMM provides contraints as a combination "
576 "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
577 "by the \"shake_tol\" option.");
579 if (ir->nwall != 0)
580 gmx_fatal(FARGS,"OpenMM does not support walls.");
582 if (ir->ePull != epullNO)
583 gmx_fatal(FARGS,"OpenMM does not support pulling.");
585 /* check for interaction types */
586 for (i = 0; i < F_EPOT; i++)
588 if (!(i == F_CONSTR ||
589 i == F_SETTLE ||
590 i == F_BONDS ||
591 i == F_UREY_BRADLEY ||
592 i == F_ANGLES ||
593 i == F_PDIHS ||
594 i == F_RBDIHS ||
595 i == F_LJ14 ||
596 i == F_GB12 || /* The GB parameters are hardcoded both in */
597 i == F_GB13 || /* Gromacs and OpenMM */
598 i == F_GB14 ) &&
599 top->idef.il[i].nr > 0)
601 gmx_fatal(FARGS, "OpenMM does not support (some) of the provided interaction "
602 "type(s) (%s) ", interaction_function[i].longname);
606 if (ir->efep != efepNO)
607 gmx_fatal(FARGS,"OpenMM does not support free energy calculations.");
609 if (ir->opts.ngacc > 1)
610 gmx_fatal(FARGS,"OpenMM does not support non-equilibrium MD (accelerated groups).");
612 if (IR_ELEC_FIELD(*ir))
613 gmx_fatal(FARGS,"OpenMM does not support electric fields.");
615 if (ir->bQMMM)
616 gmx_fatal(FARGS,"OpenMM does not support QMMM calculations.");
618 if (ir->rcoulomb != ir->rvdw)
619 gmx_fatal(FARGS,"OpenMM uses a single cutoff for both Coulomb "
620 "and VdW interactions. Please set rcoulomb equal to rvdw.");
622 if (EEL_FULL(ir->coulombtype))
624 if (ir->ewald_geometry == eewg3DC)
625 gmx_fatal(FARGS,"OpenMM supports only Ewald 3D geometry.");
626 if (ir->epsilon_surface != 0)
627 gmx_fatal(FARGS,"OpenMM does not support dipole correction in Ewald summation.");
630 if (TRICLINIC(state->box))
632 gmx_fatal(FARGS,"OpenMM does not support triclinic unit cells.");
635 /* XXX this is just debugging code to disable the combination rule check */
636 if ( isStringEqNCase(opt->getOptionValue("check-combrule"), "yes") )
638 /* As OpenMM by default uses hardcoded combination rules
639 sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j)
640 we need to check whether the force field params obey this
641 and if not, we can't use this force field so we exit
642 grace-fatal-fully. */
643 real *nbfp = fr->nbfp;
644 natoms = fr->ntype;
645 if (debug)
647 fprintf(debug, ">> Atom parameters: <<\n%10s%5s %5s %5s %5s COMB\n",
648 "", "i-j", "j-i", "i-i", "j-j");
650 /* loop over all i-j atom pairs and verify if
651 sigma_ij = sigma_ji = sigma_comb and eps_ij = eps_ji = eps_comb */
652 for (i = 0; i < natoms; i++)
654 /* i-i */
655 c12 = C12(nbfp, natoms, i, i);
656 c6 = C6(nbfp, natoms, i, i);
657 convert_c_12_6(c12, c6, &sigma_ii, &eps_ii);
659 for (j = 0; j < i; j++)
661 /* i-j */
662 c12 = C12(nbfp, natoms, i, j);
663 c6 = C6(nbfp, natoms, i, j);
664 convert_c_12_6(c12, c6, &sigma_ij, &eps_ij);
665 /* j-i */
666 c12 = C12(nbfp, natoms, j, i);
667 c6 = C6(nbfp, natoms, j, i);
668 convert_c_12_6(c12, c6, &sigma_ji, &eps_ji);
669 /* j-j */
670 c12 = C12(nbfp, natoms, j, j);
671 c6 = C6(nbfp, natoms, j, j);
672 convert_c_12_6(c12, c6, &sigma_jj, &eps_jj);
673 /* OpenMM hardcoded combination rules */
674 sigma_comb = COMBRULE_SIGMA(sigma_ii, sigma_jj);
675 eps_comb = COMBRULE_EPS(eps_ii, eps_jj);
677 if (debug)
679 fprintf(debug, "i=%-3d j=%-3d", i, j);
680 fprintf(debug, "%-11s", "sigma");
681 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",
682 sigma_ij, sigma_ji, sigma_ii, sigma_jj, sigma_comb);
683 fprintf(debug, "%11s%-11s", "", "epsilon");
684 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",
685 eps_ij, eps_ji, eps_ii, eps_jj, eps_comb);
688 /* check the values against the rule used by omm */
689 if((fabs(eps_ij) > COMBRULE_CHK_TOL &&
690 fabs(eps_ji) > COMBRULE_CHK_TOL) &&
691 (fabs(sigma_comb - sigma_ij) > COMBRULE_CHK_TOL ||
692 fabs(sigma_comb - sigma_ji) > COMBRULE_CHK_TOL ||
693 fabs(eps_comb - eps_ij) > COMBRULE_CHK_TOL ||
694 fabs(eps_comb - eps_ji) > COMBRULE_CHK_TOL ))
696 gmx_fatal(FARGS,
697 "The combination rules of the used force-field do not "
698 "match the one supported by OpenMM: "
699 "sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j). "
700 "Switch to a force-field that uses these rules in order to "
701 "simulate this system using OpenMM.\n");
705 if (debug) { fprintf(debug, ">><<\n\n"); }
707 /* if we got here, log that everything is fine */
708 if (debug)
710 fprintf(debug, ">> The combination rule of the used force matches the one used by OpenMM.\n");
712 fprintf(fplog, "The combination rule of the force used field matches the one used by OpenMM.\n");
714 } /* if (are we checking the combination rules) ... */
719 * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to
720 * the OpenMMData.
722 * Various gromacs data structures are passed that contain the parameters, state and
723 * other porperties of the system to simulate. These serve as input for initializing
724 * OpenMM. Besides, a set of misc action are taken:
725 * - OpenMM plugins are loaded;
726 * - platform options in \p platformOptStr are parsed and checked;
727 * - Gromacs parameters are checked for OpenMM support and consistency;
728 * - after the OpenMM is initialized memtest executed in the same GPU context.
730 * \param[in] fplog Gromacs log file handler.
731 * \param[in] platformOptStr Platform option string.
732 * \param[in] ir The Gromacs input parameters, see ::t_inputrec
733 * \param[in] top_global Gromacs system toppology, \see ::gmx_mtop_t
734 * \param[in] top Gromacs node local topology, \see gmx_localtop_t
735 * \param[in] mdatoms Gromacs atom parameters, \see ::t_mdatoms
736 * \param[in] fr \see ::t_forcerec
737 * \param[in] state Gromacs systems state, \see ::t_state
738 * \returns Pointer to a
741 void* openmm_init(FILE *fplog, const char *platformOptStr,
742 t_inputrec *ir,
743 gmx_mtop_t *top_global, gmx_localtop_t *top,
744 t_mdatoms *mdatoms, t_forcerec *fr, t_state *state)
747 char warn_buf[STRLEN];
748 static bool hasLoadedPlugins = false;
749 string usedPluginDir;
750 int devId;
754 if (!hasLoadedPlugins)
756 vector<string> loadedPlugins;
757 /* Look for OpenMM plugins at various locations (listed in order of priority):
758 - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
759 - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
760 - at the default location assumed by OpenMM
762 /* env var */
763 char *pluginDir = getenv("OPENMM_PLUGIN_DIR");
764 trim(pluginDir);
765 /* no env var or empty */
766 if (pluginDir != NULL && *pluginDir != '\0')
768 loadedPlugins = Platform::loadPluginsFromDirectory(pluginDir);
769 if (loadedPlugins.size() > 0)
771 hasLoadedPlugins = true;
772 usedPluginDir = pluginDir;
774 else
776 gmx_fatal(FARGS, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
777 "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!",
778 pluginDir);
782 /* macro set at build time */
783 #ifdef OPENMM_PLUGIN_DIR
784 if (!hasLoadedPlugins)
786 loadedPlugins = Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR);
787 if (loadedPlugins.size() > 0)
789 hasLoadedPlugins = true;
790 usedPluginDir = OPENMM_PLUGIN_DIR;
793 #endif
794 /* default loocation */
795 if (!hasLoadedPlugins)
797 loadedPlugins = Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
798 if (loadedPlugins.size() > 0)
800 hasLoadedPlugins = true;
801 usedPluginDir = Platform::getDefaultPluginsDirectory();
805 /* if there are still no plugins loaded there won't be any */
806 if (!hasLoadedPlugins)
808 gmx_fatal(FARGS, "No OpenMM plugins were found! You can provide the"
809 " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir);
812 fprintf(fplog, "\nPlugins loaded from directory %s:\t", usedPluginDir.c_str());
813 for (int i = 0; i < (int)loadedPlugins.size(); i++)
815 fprintf(fplog, "%s, ", loadedPlugins[i].c_str());
817 fprintf(fplog, "\n");
820 /* parse option string */
821 GmxOpenMMPlatformOptions *opt = new GmxOpenMMPlatformOptions(platformOptStr);
822 devId = atoi(opt->getOptionValue("deviceid").c_str());
824 if (debug)
826 opt->print();
829 /* check wheter Gromacs options compatibility with OpenMM */
830 checkGmxOptions(fplog, opt, ir, top, fr, state);
832 // Create the system.
833 const t_idef& idef = top->idef;
834 const int numAtoms = top_global->natoms;
835 const int numConstraints = idef.il[F_CONSTR].nr/3;
836 const int numSettle = idef.il[F_SETTLE].nr/2;
837 const int numBonds = idef.il[F_BONDS].nr/3;
838 const int numUB = idef.il[F_UREY_BRADLEY].nr/4;
839 const int numAngles = idef.il[F_ANGLES].nr/4;
840 const int numPeriodic = idef.il[F_PDIHS].nr/5;
841 const int numRB = idef.il[F_RBDIHS].nr/5;
842 const int num14 = idef.il[F_LJ14].nr/3;
843 System* sys = new System();
844 if (ir->nstcomm > 0)
845 sys->addForce(new CMMotionRemover(ir->nstcomm));
847 // Set bonded force field terms.
848 const int* bondAtoms = (int*) idef.il[F_BONDS].iatoms;
849 HarmonicBondForce* bondForce = new HarmonicBondForce();
850 sys->addForce(bondForce);
851 int offset = 0;
852 for (int i = 0; i < numBonds; ++i)
854 int type = bondAtoms[offset++];
855 int atom1 = bondAtoms[offset++];
856 int atom2 = bondAtoms[offset++];
857 bondForce->addBond(atom1, atom2,
858 idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
860 // Urey-Bradley includes both the angle and bond potential for 1-3 interactions
861 const int* ubAtoms = (int*) idef.il[F_UREY_BRADLEY].iatoms;
862 HarmonicBondForce* ubBondForce = new HarmonicBondForce();
863 HarmonicAngleForce* ubAngleForce = new HarmonicAngleForce();
864 sys->addForce(ubBondForce);
865 sys->addForce(ubAngleForce);
866 offset = 0;
867 for (int i = 0; i < numUB; ++i)
869 int type = ubAtoms[offset++];
870 int atom1 = ubAtoms[offset++];
871 int atom2 = ubAtoms[offset++];
872 int atom3 = ubAtoms[offset++];
873 ubBondForce->addBond(atom1, atom3,
874 idef.iparams[type].u_b.r13, idef.iparams[type].u_b.kUB);
875 ubAngleForce->addAngle(atom1, atom2, atom3,
876 idef.iparams[type].u_b.theta*M_PI/180.0, idef.iparams[type].u_b.ktheta);
878 const int* angleAtoms = (int*) idef.il[F_ANGLES].iatoms;
879 HarmonicAngleForce* angleForce = new HarmonicAngleForce();
880 sys->addForce(angleForce);
881 offset = 0;
882 for (int i = 0; i < numAngles; ++i)
884 int type = angleAtoms[offset++];
885 int atom1 = angleAtoms[offset++];
886 int atom2 = angleAtoms[offset++];
887 int atom3 = angleAtoms[offset++];
888 angleForce->addAngle(atom1, atom2, atom3,
889 idef.iparams[type].harmonic.rA*M_PI/180.0, idef.iparams[type].harmonic.krA);
891 const int* periodicAtoms = (int*) idef.il[F_PDIHS].iatoms;
892 PeriodicTorsionForce* periodicForce = new PeriodicTorsionForce();
893 sys->addForce(periodicForce);
894 offset = 0;
895 for (int i = 0; i < numPeriodic; ++i)
897 int type = periodicAtoms[offset++];
898 int atom1 = periodicAtoms[offset++];
899 int atom2 = periodicAtoms[offset++];
900 int atom3 = periodicAtoms[offset++];
901 int atom4 = periodicAtoms[offset++];
902 periodicForce->addTorsion(atom1, atom2, atom3, atom4,
903 idef.iparams[type].pdihs.mult,
904 idef.iparams[type].pdihs.phiA*M_PI/180.0,
905 idef.iparams[type].pdihs.cpA);
907 const int* rbAtoms = (int*) idef.il[F_RBDIHS].iatoms;
908 RBTorsionForce* rbForce = new RBTorsionForce();
909 sys->addForce(rbForce);
910 offset = 0;
911 for (int i = 0; i < numRB; ++i)
913 int type = rbAtoms[offset++];
914 int atom1 = rbAtoms[offset++];
915 int atom2 = rbAtoms[offset++];
916 int atom3 = rbAtoms[offset++];
917 int atom4 = rbAtoms[offset++];
918 rbForce->addTorsion(atom1, atom2, atom3, atom4,
919 idef.iparams[type].rbdihs.rbcA[0], idef.iparams[type].rbdihs.rbcA[1],
920 idef.iparams[type].rbdihs.rbcA[2], idef.iparams[type].rbdihs.rbcA[3],
921 idef.iparams[type].rbdihs.rbcA[4], idef.iparams[type].rbdihs.rbcA[5]);
924 // Set nonbonded parameters and masses.
925 int ntypes = fr->ntype;
926 int* types = mdatoms->typeA;
927 real* nbfp = fr->nbfp;
928 real* charges = mdatoms->chargeA;
929 real* masses = mdatoms->massT;
930 NonbondedForce* nonbondedForce = new NonbondedForce();
931 sys->addForce(nonbondedForce);
933 switch (ir->ePBC)
935 case epbcNONE:
936 if (ir->rcoulomb == 0)
938 nonbondedForce->setNonbondedMethod(NonbondedForce::NoCutoff);
940 else
942 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
944 break;
945 case epbcXYZ:
946 switch (ir->coulombtype)
948 case eelRF:
949 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
950 break;
952 case eelEWALD:
953 nonbondedForce->setNonbondedMethod(NonbondedForce::Ewald);
954 break;
956 case eelPME:
957 nonbondedForce->setNonbondedMethod(NonbondedForce::PME);
958 break;
960 default:
961 gmx_fatal(FARGS,"Internal error: you should not see this message, it that the"
962 "electrosatics option check failed. Please report this error!");
964 sys->setPeriodicBoxVectors(Vec3(state->box[0][0], 0, 0),
965 Vec3(0, state->box[1][1], 0), Vec3(0, 0, state->box[2][2]));
966 nonbondedForce->setCutoffDistance(ir->rcoulomb);
968 break;
969 default:
970 gmx_fatal(FARGS,"OpenMM supports only full periodic boundary conditions "
971 "(pbc = xyz), or none (pbc = no).");
975 /* Fix for PME and Ewald error tolerance
977 * OpenMM uses approximate formulas to calculate the Ewald parameter:
978 * alpha = (1.0/cutoff)*sqrt(-log(2.0*tolerlance));
979 * and the grid spacing for PME:
980 * gridX = ceil(alpha*box[0][0]/pow(0.5*tol, 0.2));
981 * gridY = ceil(alpha*box[1][1]/pow(0.5*tol, 0.2));
982 * gridZ = ceil(alpha*box[2][2]/pow(0.5*tol, 0.2));
984 * It overestimates the precision and setting it to
985 * (500 x ewald_rtol) seems to give a reasonable match to the GROMACS settings
987 * If the default ewald_rtol=1e-5 is used we silently adjust the value,
988 * otherwise a warning is issued about the action taken.
990 double corr_ewald_rtol = 500.0 * ir->ewald_rtol;
991 if ((ir->ePBC == epbcXYZ) &&
992 (ir->coulombtype == eelEWALD || ir->coulombtype == eelPME))
994 if (debug)
996 fprintf(debug, ">> ewald_rtol = %e (corrected = %e) \n",
997 ir->ewald_rtol, corr_ewald_rtol);
1000 if (fabs(ir->ewald_rtol - 1e-5) > 1e-10)
1002 gmx_warning("OpenMM uses the ewald_rtol parameter with approximate formulas "
1003 "to calculate the alpha and grid spacing parameters of the Ewald "
1004 "and PME methods. This tolerance need to be corrected in order to get "
1005 "settings close to the ones used in GROMACS. Although the internal correction "
1006 "should work for any reasonable value of ewald_rtol, using values other than "
1007 "the default 1e-5 might cause incorrect behavior.");
1009 if (corr_ewald_rtol > 1)
1011 gmx_fatal(FARGS, "The ewald_rtol accuracy term is >1 after the "
1012 "adjustment for OpenMM (%e)", corr_ewald_rtol);
1015 nonbondedForce->setEwaldErrorTolerance(corr_ewald_rtol);
1018 for (int i = 0; i < numAtoms; ++i)
1020 double c12 = nbfp[types[i]*2*ntypes+types[i]*2+1];
1021 double c6 = nbfp[types[i]*2*ntypes+types[i]*2];
1022 double sigma=0.0, epsilon=0.0;
1023 convert_c_12_6(c12, c6, &sigma, &epsilon);
1024 nonbondedForce->addParticle(charges[i], sigma, epsilon);
1025 sys->addParticle(masses[i]);
1028 // Build a table of all exclusions.
1029 vector<set<int> > exclusions(numAtoms);
1030 for (int i = 0; i < numAtoms; i++)
1032 int start = top->excls.index[i];
1033 int end = top->excls.index[i+1];
1034 for (int j = start; j < end; j++)
1035 exclusions[i].insert(top->excls.a[j]);
1038 // Record the 1-4 interactions, and remove them from the list of exclusions.
1039 const int* nb14Atoms = (int*) idef.il[F_LJ14].iatoms;
1040 offset = 0;
1041 for (int i = 0; i < num14; ++i)
1043 int type = nb14Atoms[offset++];
1044 int atom1 = nb14Atoms[offset++];
1045 int atom2 = nb14Atoms[offset++];
1046 double sigma=0, epsilon=0;
1047 convert_c_12_6(idef.iparams[type].lj14.c12A,
1048 idef.iparams[type].lj14.c6A,
1049 &sigma, &epsilon);
1050 nonbondedForce->addException(atom1, atom2,
1051 fr->fudgeQQ*charges[atom1]*charges[atom2], sigma, epsilon);
1052 exclusions[atom1].erase(atom2);
1053 exclusions[atom2].erase(atom1);
1056 // Record exclusions.
1057 for (int i = 0; i < numAtoms; i++)
1059 for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
1061 if (i < *iter)
1063 nonbondedForce->addException(i, *iter, 0.0, 1.0, 0.0);
1068 // Add GBSA if needed.
1069 if (ir->implicit_solvent == eisGBSA)
1071 gmx_warning("The OBC scale factors alpha, beta and gamma are hardcoded in OpenMM with the default Gromacs values.");
1072 t_atoms atoms = gmx_mtop_global_atoms(top_global);
1073 GBSAOBCForce* gbsa = new GBSAOBCForce();
1075 sys->addForce(gbsa);
1076 gbsa->setSoluteDielectric(ir->epsilon_r);
1077 gbsa->setSolventDielectric(ir->gb_epsilon_solvent);
1078 gbsa->setCutoffDistance(nonbondedForce->getCutoffDistance());
1079 if (nonbondedForce->getNonbondedMethod() == NonbondedForce::NoCutoff)
1080 gbsa->setNonbondedMethod(GBSAOBCForce::NoCutoff);
1081 else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic)
1082 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
1083 else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffPeriodic)
1084 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
1085 else
1086 gmx_fatal(FARGS,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
1088 for (int i = 0; i < numAtoms; ++i)
1090 gbsa->addParticle(charges[i],
1091 top_global->atomtypes.gb_radius[atoms.atom[i].type],
1092 top_global->atomtypes.S_hct[atoms.atom[i].type]);
1094 free_t_atoms(&atoms, FALSE);
1097 // Set constraints.
1098 const int* constraintAtoms = (int*) idef.il[F_CONSTR].iatoms;
1099 offset = 0;
1100 for (int i = 0; i < numConstraints; ++i)
1102 int type = constraintAtoms[offset++];
1103 int atom1 = constraintAtoms[offset++];
1104 int atom2 = constraintAtoms[offset++];
1105 sys->addConstraint(atom1, atom2, idef.iparams[type].constr.dA);
1107 const int* settleAtoms = (int*) idef.il[F_SETTLE].iatoms;
1108 offset = 0;
1109 for (int i = 0; i < numSettle; ++i)
1111 int type = settleAtoms[offset++];
1112 int oxygen = settleAtoms[offset++];
1113 sys->addConstraint(oxygen, oxygen+1, idef.iparams[type].settle.doh);
1114 sys->addConstraint(oxygen, oxygen+2, idef.iparams[type].settle.doh);
1115 sys->addConstraint(oxygen+1, oxygen+2, idef.iparams[type].settle.dhh);
1118 // Create an integrator for simulating the system.
1119 double friction = (ir->opts.tau_t[0] == 0.0 ? 0.0 : 1.0/ir->opts.tau_t[0]);
1120 Integrator* integ;
1121 if (ir->eI == eiBD)
1123 integ = new BrownianIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1124 static_cast<BrownianIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed);
1126 else if (EI_SD(ir->eI))
1128 integ = new LangevinIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1129 static_cast<LangevinIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed);
1131 else
1133 integ = new VerletIntegrator(ir->delta_t);
1134 if ( ir->etc != etcNO)
1136 real collisionFreq = ir->opts.tau_t[0] / 1000; /* tau_t (ps) / 1000 = collisionFreq (fs^-1) */
1137 AndersenThermostat* thermostat = new AndersenThermostat(ir->opts.ref_t[0], friction);
1138 sys->addForce(thermostat);
1141 integ->setConstraintTolerance(ir->shake_tol);
1143 // Create a context and initialize it.
1144 Context* context = NULL;
1147 OpenMM could automatically select the "best" GPU, however we're not't
1148 going to let it do that for now, as the current algorithm is very rudimentary
1149 and we anyway support only CUDA.
1150 if (platformOptStr == NULL || platformOptStr == "")
1152 context = new Context(*sys, *integ);
1154 else
1157 /* which platform should we use */
1158 for (int i = 0; i < (int)Platform::getNumPlatforms() && context == NULL; i++)
1160 if (isStringEqNCase(opt->getOptionValue("platform"), Platform::getPlatform(i).getName()))
1162 Platform& platform = Platform::getPlatform(i);
1163 // set standard properties
1164 platform.setPropertyDefaultValue("CudaDevice", opt->getOptionValue("deviceid"));
1165 // TODO add extra properties
1166 context = new Context(*sys, *integ, platform);
1169 if (context == NULL)
1171 gmx_fatal(FARGS, "The requested platform \"%s\" could not be found.",
1172 opt->getOptionValue("platform").c_str());
1176 Platform& platform = context->getPlatform();
1177 fprintf(fplog, "Gromacs will use the OpenMM platform: %s\n", platform.getName().c_str());
1179 const vector<string>& properties = platform.getPropertyNames();
1180 if (debug)
1182 for (int i = 0; i < (int)properties.size(); i++)
1184 fprintf(debug, ">> %s: %s\n", properties[i].c_str(),
1185 platform.getPropertyValue(*context, properties[i]).c_str());
1189 /* only for CUDA */
1190 if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1192 /* For now this is just to double-check if OpenMM selected the GPU we wanted,
1193 but when we'll let OpenMM select the GPU automatically, it will query the devideId.
1195 int tmp;
1196 if (!from_string<int>(tmp, platform.getPropertyValue(*context, "CudaDevice"), std::dec))
1198 gmx_fatal(FARGS, "Internal error: couldn't determine the device selected by OpenMM");
1199 if (tmp != devId)
1201 gmx_fatal(FARGS, "Internal error: OpenMM is using device #%d"
1202 "while initialized for device #%d", tmp, devId);
1206 /* check GPU compatibility */
1207 char gpuname[STRLEN];
1208 devId = atoi(opt->getOptionValue("deviceid").c_str());
1209 if (!is_supported_cuda_gpu(-1, gpuname))
1211 if (!gmx_strcasecmp(opt->getOptionValue("force-device").c_str(), "yes"))
1213 sprintf(warn_buf, "Non-supported GPU selected (#%d, %s), forced continuing."
1214 "Note, that the simulation can be slow or it migth even crash.",
1215 devId, gpuname);
1216 fprintf(fplog, "%s\n", warn_buf);
1217 gmx_warning(warn_buf);
1219 else
1221 gmx_fatal(FARGS, "The selected GPU (#%d, %s) is not supported by Gromacs! "
1222 "Most probably you have a low-end GPU which would not perform well, "
1223 "or new hardware that has not been tested with the current release. "
1224 "If you still want to try using the device, use the force-device=yes option.",
1225 devId, gpuname);
1228 else
1230 fprintf(fplog, "Gromacs will run on the GPU #%d (%s).\n", devId, gpuname);
1234 /* only for CUDA */
1235 if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1237 /* pre-simulation memtest */
1238 runMemtest(fplog, -1, "Pre", opt);
1241 vector<Vec3> pos(numAtoms);
1242 vector<Vec3> vel(numAtoms);
1243 for (int i = 0; i < numAtoms; ++i)
1245 pos[i] = Vec3(state->x[i][0], state->x[i][1], state->x[i][2]);
1246 vel[i] = Vec3(state->v[i][0], state->v[i][1], state->v[i][2]);
1248 context->setPositions(pos);
1249 context->setVelocities(vel);
1251 // Return a structure containing the system, integrator, and context.
1252 OpenMMData* data = new OpenMMData();
1253 data->system = sys;
1254 data->integrator = integ;
1255 data->context = context;
1256 data->removeCM = (ir->nstcomm > 0);
1257 data->platformOpt = opt;
1258 return data;
1260 catch (std::exception& e)
1262 gmx_fatal(FARGS, "OpenMM exception caught while initializating: %s", e.what());
1264 return NULL; /* just to avoid warnings */
1268 * \brief Integrate one step.
1270 * \param[in] data OpenMMData object created by openmm_init().
1272 void openmm_take_one_step(void* data)
1274 // static int step = 0; printf("----> taking step #%d\n", step++);
1277 static_cast<OpenMMData*>(data)->integrator->step(1);
1279 catch (std::exception& e)
1281 gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1286 * \brief Integrate n steps.
1288 * \param[in] data OpenMMData object created by openmm_init().
1290 void openmm_take_steps(void* data, int nstep)
1294 static_cast<OpenMMData*>(data)->integrator->step(nstep);
1296 catch (std::exception& e)
1298 gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1303 * \brief Clean up the data structures cretead for OpenMM.
1305 * \param[in] log Log file pointer.
1306 * \param[in] data OpenMMData object created by openmm_init().
1308 void openmm_cleanup(FILE* fplog, void* data)
1310 OpenMMData* d = static_cast<OpenMMData*>(data);
1311 /* only for CUDA */
1312 if (isStringEqNCase(d->platformOpt->getOptionValue("platform"), "CUDA"))
1314 /* post-simulation memtest */
1315 runMemtest(fplog, -1, "Post", d->platformOpt);
1317 delete d->system;
1318 delete d->integrator;
1319 delete d->context;
1320 delete d->platformOpt;
1321 delete d;
1325 * \brief Copy the current state information from OpenMM into the Gromacs data structures.
1327 * This function results in the requested proprties to be copied from the
1328 * GPU to host. As this represents a bottleneck, the frequency of pulling data
1329 * should be minimized.
1331 * \param[in] data OpenMMData object created by openmm_init().
1332 * \param[out] time Simulation time for which the state was created.
1333 * \param[out] state State of the system: coordinates and velocities.
1334 * \param[out] f Forces.
1335 * \param[out] enerd Energies.
1336 * \param[in] includePos True if coordinates are requested.
1337 * \param[in] includeVel True if velocities are requested.
1338 * \param[in] includeForce True if forces are requested.
1339 * \param[in] includeEnergy True if energies are requested.
1341 void openmm_copy_state(void *data,
1342 t_state *state, double *time,
1343 rvec f[], gmx_enerdata_t *enerd,
1344 bool includePos, bool includeVel, bool includeForce, bool includeEnergy)
1346 int types = 0;
1347 if (includePos)
1348 types += State::Positions;
1349 if (includeVel)
1350 types += State::Velocities;
1351 if (includeForce)
1352 types += State::Forces;
1353 if (includeEnergy)
1354 types += State::Energy;
1355 if (types == 0)
1356 return;
1359 State currentState = static_cast<OpenMMData*>(data)->context->getState(types);
1360 int numAtoms = static_cast<OpenMMData*>(data)->system->getNumParticles();
1361 if (includePos)
1363 for (int i = 0; i < numAtoms; i++)
1365 Vec3 x = currentState.getPositions()[i];
1366 state->x[i][0] = x[0];
1367 state->x[i][1] = x[1];
1368 state->x[i][2] = x[2];
1371 if (includeVel)
1373 for (int i = 0; i < numAtoms; i++)
1375 Vec3 v = currentState.getVelocities()[i];
1376 state->v[i][0] = v[0];
1377 state->v[i][1] = v[1];
1378 state->v[i][2] = v[2];
1381 if (includeForce)
1383 for (int i = 0; i < numAtoms; i++)
1385 Vec3 force = currentState.getForces()[i];
1386 f[i][0] = force[0];
1387 f[i][1] = force[1];
1388 f[i][2] = force[2];
1391 if (includeEnergy)
1393 int numConstraints = static_cast<OpenMMData*>(data)->system->getNumConstraints();
1394 int dof = 3*numAtoms-numConstraints;
1395 if (static_cast<OpenMMData*>(data)->removeCM)
1396 dof -= 3;
1397 enerd->term[F_EPOT] = currentState.getPotentialEnergy();
1398 enerd->term[F_EKIN] = currentState.getKineticEnergy();
1399 enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
1400 enerd->term[F_TEMP] = 2.0*enerd->term[F_EKIN]/dof/BOLTZ;
1402 *time = currentState.getTime();
1404 catch (std::exception& e)
1406 gmx_fatal(FARGS, "OpenMM exception caught while retrieving state information: %s", e.what());