1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
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
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
46 #include <types/simple.h>
61 #include "gmx_fatal.h"
66 #include "gmx_gpu_utils.h"
67 #include "mtop_util.h"
69 #include "openmm_wrapper.h"
71 using namespace OpenMM;
74 #define MEM_ERR_MSG(str) \
75 "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
76 "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
77 "overclocked and that the device is properly cooled.\n", (str)
80 #define COMBRULE_CHK_TOL 1e-6
81 #define COMBRULE_SIGMA(sig1, sig2) (((sig1) + (sig2))/2)
82 #define COMBRULE_EPS(eps1, eps2) (sqrt((eps1) * (eps2)))
85 * \brief Convert string to integer type.
86 * \param[in] s String to convert from.
87 * \param[in] f Basefield format flag that takes any of the following I/O
88 * manipulators: dec, hex, oct.
89 * \param[out] t Destination variable to convert to.
92 static gmx_bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
95 return !(iss >> f >> t).fail();
99 * \brief Split string around a given delimiter.
100 * \param[in] s String to split.
101 * \param[in] delim Delimiter character.
102 * \returns Vector of strings found in \p s.
104 static vector<string> split(const string &s, char delim)
106 vector<string> elems;
109 while (getline(ss, item, delim))
111 if (item.length() != 0)
112 elems.push_back(item);
118 * \brief Split a string of the form "option=value" into "option" and "value" strings.
119 * This string corresponds to one option and the associated value from the option list
120 * in the mdrun -device argument.
122 * \param[in] s A string containing an "option=value" pair that needs to be split up.
123 * \param[out] opt The name of the option.
124 * \param[out] val Value of the option.
126 static void splitOptionValue(const string &s, string &opt, string &val)
128 size_t eqPos = s.find('=');
129 if (eqPos != string::npos)
131 opt = s.substr(0, eqPos);
132 if (eqPos != s.length()) val = s.substr(eqPos+1);
137 * \brief Compare two strings ignoring case.
138 * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
139 * \param[in] s1 String.
140 * \param[in] s2 String.
141 * \returns Similarly to the C function strncasecmp(), the return value is an
142 integer less than, equal to, or greater than 0 if \p s1 less than,
143 identical to, or greater than \p s2.
145 static gmx_bool isStringEqNCase(const string s1, const string s2)
147 return (gmx_strncasecmp(s1.c_str(), s2.c_str(), max(s1.length(), s2.length())) == 0);
151 * \brief Convert string to upper case.
153 * \param[in] s String to convert to uppercase.
154 * \returns The given string converted to uppercase.
156 static string toUpper(const string &s)
159 std::transform(stmp.begin(), stmp.end(), stmp.begin(), static_cast < int(*)(int) > (toupper));
164 \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms,
165 GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
166 GmxOpenMMPlatformOptions#force_dev. */
168 #define SIZEOF_PLATFORMS 2 // 2
169 #define SIZEOF_MEMTESTS 3
170 #define SIZEOF_DEVICEIDS 1
171 #define SIZEOF_FORCE_DEV 2
173 #define SIZEOF_CHECK_COMBRULE 2
176 /*! Possible platform options in the mdrun -device option. */
177 static const char *devOptStrings[] = { "platform", "deviceid", "memtest", "force-device", "check-combrule" };
179 /*! Enumerated platform options in the mdrun -device option. */
189 * \brief Class to extract and manage the platform options in the mdrun -device option.
192 class GmxOpenMMPlatformOptions
195 GmxOpenMMPlatformOptions(const char *opt);
196 ~GmxOpenMMPlatformOptions() { options.clear(); }
197 string getOptionValue(const string &opt);
198 void remOption(const string &opt);
201 void setOption(const string &opt, const string &val);
203 map<string, string> options; /*!< Data structure to store the option (name, value) pairs. */
205 static const char * const platforms[SIZEOF_PLATFORMS]; /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
206 static const char * const memtests[SIZEOF_MEMTESTS]; /*!< Available types of memory tests, also valid
207 any positive integer >=15; size #SIZEOF_MEMTESTS */
208 static const char * const deviceid[SIZEOF_DEVICEIDS]; /*!< Possible values for deviceid option;
209 also valid any positive integer; size #SIZEOF_DEVICEIDS */
210 static const char * const force_dev[SIZEOF_FORCE_DEV]; /*!< Possible values for for force-device option;
211 size #SIZEOF_FORCE_DEV */
212 static const char * const check_combrule[SIZEOF_CHECK_COMBRULE]; /* XXX temporary debug feature to
213 turn off combination rule check */
216 const char * const GmxOpenMMPlatformOptions::platforms[SIZEOF_PLATFORMS]
217 = {"CUDA", "Reference"};
218 //= { "Reference", "CUDA" /*,"OpenCL"*/ };
219 const char * const GmxOpenMMPlatformOptions::memtests[SIZEOF_MEMTESTS]
220 = { "15", "full", "off" };
221 const char * const GmxOpenMMPlatformOptions::deviceid[SIZEOF_DEVICEIDS]
223 const char * const GmxOpenMMPlatformOptions::force_dev[SIZEOF_FORCE_DEV]
225 const char * const GmxOpenMMPlatformOptions::check_combrule[SIZEOF_CHECK_COMBRULE]
230 * Takes the option list, parses it, checks the options and their values for validity.
231 * When certain options are not provided by the user, as default value the first item
232 * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms,
233 * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
234 * GmxOpenMMPlatformOptions#force_dev).
235 * \param[in] optionString Option list part of the mdrun -device parameter.
237 GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString)
239 // set default values
240 setOption("platform", platforms[0]);
241 setOption("memtest", memtests[0]);
242 setOption("deviceid", deviceid[0]);
243 setOption("force-device", force_dev[0]);
244 setOption("check-combrule", check_combrule[0]);
246 string opt(optionString);
248 // remove all whitespaces
249 opt.erase(remove_if(opt.begin(), opt.end(), ::isspace), opt.end());
250 // tokenize around ","-s
251 vector<string> tokens = split(opt, ',');
253 for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
255 string opt = "", val = "";
256 splitOptionValue(*it, opt, val);
258 if (isStringEqNCase(opt, "platform"))
260 /* no check, this will fail if platform does not exist when we try to set it */
265 if (isStringEqNCase(opt, "memtest"))
267 /* the value has to be an integer >15(s) or "full" OR "off" */
268 if (!isStringEqNCase(val, "full") && !isStringEqNCase(val, "off"))
271 if (!from_string<int>(secs, val, std::dec))
273 gmx_fatal(FARGS, "Invalid value for option memtest option: \"%s\"!", val.c_str());
277 gmx_fatal(FARGS, "Incorrect value for memtest option (%d). "
278 "Memtest needs to run for at least 15s!", secs);
285 if (isStringEqNCase(opt, "deviceid"))
288 if (!from_string<int>(id, val, std::dec) )
290 gmx_fatal(FARGS, "Invalid device id: \"%s\"!", val.c_str());
296 if (isStringEqNCase(opt, "force-device"))
299 if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
301 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
307 if (isStringEqNCase(opt, "check-combrule"))
310 if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
312 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
319 // if we got till here something went wrong
320 gmx_fatal(FARGS, "Invalid OpenMM platform option: \"%s\"!", (*it).c_str());
326 * \brief Getter function.
327 * \param[in] opt Name of the option.
328 * \returns Returns the value associated to an option.
330 string GmxOpenMMPlatformOptions::getOptionValue(const string &opt)
332 map<string, string> :: const_iterator it = options.find(toUpper(opt));
333 if (it != options.end())
344 * \brief Setter function - private, only used from contructor.
345 * \param[in] opt Name of the option.
346 * \param[in] val Value for the option.
348 void GmxOpenMMPlatformOptions::setOption(const string &opt, const string &val)
350 options[toUpper(opt)] = val;
354 * \brief Removes an option with its value from the map structure. If the option
355 * does not exist, returns without any action.
356 * \param[in] opt Name of the option.
358 void GmxOpenMMPlatformOptions::remOption(const string &opt)
360 options.erase(toUpper(opt));
364 * \brief Print option-value pairs to a file (debugging function).
366 void GmxOpenMMPlatformOptions::print()
368 cout << ">> Platform options: " << endl
369 << ">> platform = " << getOptionValue("platform") << endl
370 << ">> deviceID = " << getOptionValue("deviceid") << endl
371 << ">> memtest = " << getOptionValue("memtest") << endl
372 << ">> force-device = " << getOptionValue("force-device") << endl;
376 * \brief Container for OpenMM related data structures that represent the bridge
377 * between the Gromacs data-structures and the OpenMM library and is but it's
378 * only passed through the API functions as void to disable direct access.
383 System* system; /*! The system to simulate. */
384 Context* context; /*! The OpenMM context in which the simulation is carried out. */
385 Integrator* integrator; /*! The integrator used in the simulation. */
386 gmx_bool removeCM; /*! If \true remove venter of motion, false otherwise. */
387 GmxOpenMMPlatformOptions *platformOpt; /*! Platform options. */
391 * \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
392 * \param[in] fplog Pointer to gromacs log file.
393 * \param[in] devId Device id of the GPU to run the test on.
394 Note: as OpenMM previously creates the context,for now this is always -1.
395 * \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in
396 * stdout messages/log between memtest carried out before and after simulation.
397 * \param[in] opt Pointer to platform options object.
399 static void runMemtest(FILE* fplog, int devId, const char* pre_post, GmxOpenMMPlatformOptions *opt)
401 char strout_buf[STRLEN];
404 string s = opt->getOptionValue("memtest");
405 const char *test_type = s.c_str();
407 if (!gmx_strcasecmp(test_type, "off"))
413 if (!gmx_strcasecmp(test_type, "full"))
419 from_string<int>(which_test, test_type, std::dec);
425 gmx_fatal(FARGS, "Amount of seconds for memetest is negative (%d). ", which_test);
430 case 0: /* no memtest */
431 sprintf(strout_buf, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
432 "incorrect results!", pre_post);
433 fprintf(fplog, "%s\n", strout_buf);
434 gmx_warning(strout_buf);
437 case 1: /* quick memtest */
438 fprintf(fplog, "%s-simulation %s GPU memtest in progress...\n", pre_post, test_type);
439 fprintf(stdout, "\n%s-simulation %s GPU memtest in progress...", pre_post, test_type);
442 res = do_quick_memtest(devId);
445 case 2: /* full memtest */
446 fprintf(fplog, "%s-simulation %s memtest in progress...\n", pre_post, test_type);
447 fprintf(stdout, "\n%s-simulation %s memtest in progress...", pre_post, test_type);
450 res = do_full_memtest(devId);
453 default: /* timed memtest */
454 fprintf(fplog, "%s-simulation ~%ds memtest in progress...\n", pre_post, which_test);
455 fprintf(stdout, "\n%s-simulation ~%ds memtest in progress...", pre_post, which_test);
458 res = do_timed_memtest(devId, which_test);
465 gmx_fatal(FARGS, MEM_ERR_MSG(pre_post));
469 fprintf(fplog, "Memory test completed without errors.\n");
471 fprintf(stdout, "done, no errors detected\n");
478 * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
483 * \param[out] epsilon
485 static void convert_c_12_6(double c12, double c6, double *sigma, double *epsilon)
487 if (c12 == 0 && c6 == 0)
492 else if (c12 > 0 && c6 > 0)
494 *epsilon = (c6*c6)/(4.0*c12);
495 *sigma = pow(c12/c6, 1.0/6.0);
499 gmx_fatal(FARGS,"OpenMM only supports c6 > 0 and c12 > 0 or c6 = c12 = 0.");
504 * \brief Does gromacs option checking.
506 * Checks the gromacs mdp options for features unsupported in OpenMM, case in which
507 * interrupts the execution. It also warns the user about pecularities of OpenMM
509 * \param[in] fplog Gromacs log file pointer.
510 * \param[in] ir Gromacs input parameters, see ::t_inputrec
511 * \param[in] top Gromacs node local topology, \see gmx_localtop_t
512 * \param[in] state Gromacs state structure \see ::t_state
513 * \param[in] mdatoms Gromacs atom parameters, \see ::t_mdatoms
514 * \param[in] fr \see ::t_forcerec
515 * \param[in] state Gromacs systems state, \see ::t_state
517 static void checkGmxOptions(FILE* fplog, GmxOpenMMPlatformOptions *opt,
518 t_inputrec *ir, gmx_localtop_t *top,
519 t_forcerec *fr, t_state *state)
521 char warn_buf[STRLEN];
524 double sigma_ij=0, sigma_ji=0, sigma_ii=0, sigma_jj=0, sigma_comb;
525 double eps_ij=0, eps_ji=0, eps_ii=0, eps_jj=0, eps_comb;
527 /* Abort if unsupported critical options are present */
532 gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
535 if ( (ir->eI != eiMD) &&
537 (ir->eI != eiVVAK) &&
542 gmx_fatal(FARGS, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
546 if ( !(ir->coulombtype == eelPME ||
547 EEL_RF(ir->coulombtype) ||
548 ir->coulombtype == eelRF ||
549 ir->coulombtype == eelEWALD ||
551 (ir->coulombtype == eelCUT && ir->rcoulomb == 0 && ir->rvdw == 0) ||
552 // we could have cut-off combined with GBSA (openmm will use RF)
553 ir->implicit_solvent == eisGBSA) )
555 gmx_fatal(FARGS,"OpenMM supports only the following methods for electrostatics: "
556 "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
559 if (EEL_RF(ir->coulombtype) && ir->epsilon_rf != 0)
561 // openmm has epsilon_rf=inf hard-coded
562 gmx_warning("OpenMM will use a Reaction-Field epsilon of infinity instead of %g.",ir->epsilon_rf);
565 if (ir->etc != etcNO &&
570 gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
573 if (ir->implicit_solvent == eisGBSA &&
574 ir->gb_algorithm != egbOBC )
576 gmx_warning("OpenMM does not support the specified algorithm for Generalized Born, will use OBC instead.");
579 if (ir->opts.ngtc > 1)
580 gmx_fatal(FARGS,"OpenMM does not support multiple temperature coupling groups.");
582 if (ir->epc != epcNO)
583 gmx_warning("OpenMM supports only Monte Carlo barostat for pressure coupling.");
585 if (ir->opts.annealing[0])
586 gmx_fatal(FARGS,"OpenMM does not support simulated annealing.");
588 if (top->idef.il[F_CONSTR].nr > 0 && ir->eConstrAlg != econtSHAKE)
589 gmx_warning("OpenMM provides contraints as a combination "
590 "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
591 "by the \"shake_tol\" option.");
594 gmx_fatal(FARGS,"OpenMM does not support walls.");
596 if (ir->ePull != epullNO)
597 gmx_fatal(FARGS,"OpenMM does not support pulling.");
599 /* check for interaction types */
600 for (i = 0; i < F_EPOT; i++)
602 if (!(i == F_CONSTR ||
605 i == F_UREY_BRADLEY ||
612 i == F_GB12 || /* The GB parameters are hardcoded both in */
613 i == F_GB13 || /* Gromacs and OpenMM */
615 top->idef.il[i].nr > 0)
617 gmx_fatal(FARGS, "OpenMM does not support (some) of the provided interaction "
618 "type(s) (%s) ", interaction_function[i].longname);
622 if (ir->efep != efepNO)
623 gmx_fatal(FARGS,"OpenMM does not support free energy calculations.");
625 if (ir->opts.ngacc > 1)
626 gmx_fatal(FARGS,"OpenMM does not support non-equilibrium MD (accelerated groups).");
628 if (IR_ELEC_FIELD(*ir))
629 gmx_fatal(FARGS,"OpenMM does not support electric fields.");
632 gmx_fatal(FARGS,"OpenMM does not support QMMM calculations.");
634 if (ir->rcoulomb != ir->rvdw)
635 gmx_fatal(FARGS,"OpenMM uses a single cutoff for both Coulomb "
636 "and VdW interactions. Please set rcoulomb equal to rvdw.");
638 if (EEL_FULL(ir->coulombtype))
640 if (ir->ewald_geometry == eewg3DC)
641 gmx_fatal(FARGS,"OpenMM supports only Ewald 3D geometry.");
642 if (ir->epsilon_surface != 0)
643 gmx_fatal(FARGS,"OpenMM does not support dipole correction in Ewald summation.");
646 if (TRICLINIC(state->box))
648 gmx_fatal(FARGS,"OpenMM does not support triclinic unit cells.");
651 /* XXX this is just debugging code to disable the combination rule check */
652 if ( isStringEqNCase(opt->getOptionValue("check-combrule"), "yes") )
654 /* As OpenMM by default uses hardcoded combination rules
655 sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j)
656 we need to check whether the force field params obey this
657 and if not, we can't use this force field so we exit
658 grace-fatal-fully. */
659 real *nbfp = fr->nbfp;
663 fprintf(debug, ">> Atom parameters: <<\n%10s%5s %5s %5s %5s COMB\n",
664 "", "i-j", "j-i", "i-i", "j-j");
666 /* loop over all i-j atom pairs and verify if
667 sigma_ij = sigma_ji = sigma_comb and eps_ij = eps_ji = eps_comb */
668 for (i = 0; i < natoms; i++)
671 c12 = C12(nbfp, natoms, i, i);
672 c6 = C6(nbfp, natoms, i, i);
673 convert_c_12_6(c12, c6, &sigma_ii, &eps_ii);
675 for (j = 0; j < i; j++)
678 c12 = C12(nbfp, natoms, i, j);
679 c6 = C6(nbfp, natoms, i, j);
680 convert_c_12_6(c12, c6, &sigma_ij, &eps_ij);
682 c12 = C12(nbfp, natoms, j, i);
683 c6 = C6(nbfp, natoms, j, i);
684 convert_c_12_6(c12, c6, &sigma_ji, &eps_ji);
686 c12 = C12(nbfp, natoms, j, j);
687 c6 = C6(nbfp, natoms, j, j);
688 convert_c_12_6(c12, c6, &sigma_jj, &eps_jj);
689 /* OpenMM hardcoded combination rules */
690 sigma_comb = COMBRULE_SIGMA(sigma_ii, sigma_jj);
691 eps_comb = COMBRULE_EPS(eps_ii, eps_jj);
695 fprintf(debug, "i=%-3d j=%-3d", i, j);
696 fprintf(debug, "%-11s", "sigma");
697 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",
698 sigma_ij, sigma_ji, sigma_ii, sigma_jj, sigma_comb);
699 fprintf(debug, "%11s%-11s", "", "epsilon");
700 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",
701 eps_ij, eps_ji, eps_ii, eps_jj, eps_comb);
704 /* check the values against the rule used by omm */
705 if((fabs(eps_ij) > COMBRULE_CHK_TOL &&
706 fabs(eps_ji) > COMBRULE_CHK_TOL) &&
707 (fabs(sigma_comb - sigma_ij) > COMBRULE_CHK_TOL ||
708 fabs(sigma_comb - sigma_ji) > COMBRULE_CHK_TOL ||
709 fabs(eps_comb - eps_ij) > COMBRULE_CHK_TOL ||
710 fabs(eps_comb - eps_ji) > COMBRULE_CHK_TOL ))
713 "The combination rules of the used force-field do not "
714 "match the one supported by OpenMM: "
715 "sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j). "
716 "Switch to a force-field that uses these rules in order to "
717 "simulate this system using OpenMM.\n");
721 if (debug) { fprintf(debug, ">><<\n\n"); }
723 /* if we got here, log that everything is fine */
726 fprintf(debug, ">> The combination rule of the used force matches the one used by OpenMM.\n");
728 fprintf(fplog, "The combination rule of the used force field matches the one used by OpenMM.\n");
730 } /* if (are we checking the combination rules) ... */
735 * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to
738 * Various gromacs data structures are passed that contain the parameters, state and
739 * other porperties of the system to simulate. These serve as input for initializing
740 * OpenMM. Besides, a set of misc action are taken:
741 * - OpenMM plugins are loaded;
742 * - platform options in \p platformOptStr are parsed and checked;
743 * - Gromacs parameters are checked for OpenMM support and consistency;
744 * - after the OpenMM is initialized memtest executed in the same GPU context.
746 * \param[in] fplog Gromacs log file handler.
747 * \param[in] platformOptStr Platform option string.
748 * \param[in] ir The Gromacs input parameters, see ::t_inputrec
749 * \param[in] top_global Gromacs system toppology, \see ::gmx_mtop_t
750 * \param[in] top Gromacs node local topology, \see gmx_localtop_t
751 * \param[in] mdatoms Gromacs atom parameters, \see ::t_mdatoms
752 * \param[in] fr \see ::t_forcerec
753 * \param[in] state Gromacs systems state, \see ::t_state
754 * \returns Pointer to a
757 void* openmm_init(FILE *fplog, const char *platformOptStr,
759 gmx_mtop_t *top_global, gmx_localtop_t *top,
760 t_mdatoms *mdatoms, t_forcerec *fr, t_state *state)
763 char warn_buf[STRLEN];
764 static gmx_bool hasLoadedPlugins = false;
765 string usedPluginDir;
770 if (!hasLoadedPlugins)
772 vector<string> loadedPlugins;
773 /* Look for OpenMM plugins at various locations (listed in order of priority):
774 - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
775 - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
776 - at the default location assumed by OpenMM
779 char *pluginDir = getenv("OPENMM_PLUGIN_DIR");
781 /* no env var or empty */
782 if (pluginDir != NULL && *pluginDir != '\0')
784 loadedPlugins = Platform::loadPluginsFromDirectory(pluginDir);
785 if (loadedPlugins.size() > 0)
787 hasLoadedPlugins = true;
788 usedPluginDir = pluginDir;
792 gmx_fatal(FARGS, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
793 "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!",
798 /* macro set at build time */
799 #ifdef OPENMM_PLUGIN_DIR
800 if (!hasLoadedPlugins)
802 loadedPlugins = Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR);
803 if (loadedPlugins.size() > 0)
805 hasLoadedPlugins = true;
806 usedPluginDir = OPENMM_PLUGIN_DIR;
810 /* default loocation */
811 if (!hasLoadedPlugins)
813 loadedPlugins = Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
814 if (loadedPlugins.size() > 0)
816 hasLoadedPlugins = true;
817 usedPluginDir = Platform::getDefaultPluginsDirectory();
821 /* if there are still no plugins loaded there won't be any */
822 if (!hasLoadedPlugins)
824 gmx_fatal(FARGS, "No OpenMM plugins were found! You can provide the"
825 " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir);
828 fprintf(fplog, "\nOpenMM plugins loaded from directory %s:\t", usedPluginDir.c_str());
829 for (int i = 0; i < (int)loadedPlugins.size(); i++)
831 fprintf(fplog, "%s, ", loadedPlugins[i].c_str());
833 fprintf(fplog, "\n");
836 /* parse option string */
837 GmxOpenMMPlatformOptions *opt = new GmxOpenMMPlatformOptions(platformOptStr);
838 devId = atoi(opt->getOptionValue("deviceid").c_str());
845 /* check wheter Gromacs options compatibility with OpenMM */
846 checkGmxOptions(fplog, opt, ir, top, fr, state);
848 /* Create the system. */
849 const t_idef& idef = top->idef;
850 const int numAtoms = top_global->natoms;
851 const int numConstraints = idef.il[F_CONSTR].nr/3;
852 const int numSettle = idef.il[F_SETTLE].nr/2;
853 const int numBonds = idef.il[F_BONDS].nr/3;
854 const int numUB = idef.il[F_UREY_BRADLEY].nr/4;
855 const int numAngles = idef.il[F_ANGLES].nr/4;
856 const int numPeriodic = idef.il[F_PDIHS].nr/5;
857 const int numPeriodicImproper = idef.il[F_PIDIHS].nr/5;
858 const int numRB = idef.il[F_RBDIHS].nr/5;
859 const int numImproperDih = idef.il[F_IDIHS].nr/5;
860 const int num14 = idef.il[F_LJ14].nr/3;
861 System* sys = new System();
863 sys->addForce(new CMMotionRemover(ir->nstcomm));
865 /* Set bonded force field terms. */
868 * CUDA platform currently doesn't support more than one
869 * instance of a force object, so we pack all forces that
870 * use the same form into one.
873 const int* bondAtoms = (int*) idef.il[F_BONDS].iatoms;
874 HarmonicBondForce* bondForce = new HarmonicBondForce();
875 sys->addForce(bondForce);
877 for (int i = 0; i < numBonds; ++i)
879 int type = bondAtoms[offset++];
880 int atom1 = bondAtoms[offset++];
881 int atom2 = bondAtoms[offset++];
882 bondForce->addBond(atom1, atom2,
883 idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
886 /* Set the angle force field terms */
887 const int* angleAtoms = (int*) idef.il[F_ANGLES].iatoms;
888 HarmonicAngleForce* angleForce = new HarmonicAngleForce();
889 sys->addForce(angleForce);
891 for (int i = 0; i < numAngles; ++i)
893 int type = angleAtoms[offset++];
894 int atom1 = angleAtoms[offset++];
895 int atom2 = angleAtoms[offset++];
896 int atom3 = angleAtoms[offset++];
897 angleForce->addAngle(atom1, atom2, atom3,
898 idef.iparams[type].harmonic.rA*M_PI/180.0, idef.iparams[type].harmonic.krA);
901 /* Urey-Bradley includes both the angle and bond potential for 1-3 interactions */
902 const int* ubAtoms = (int*) idef.il[F_UREY_BRADLEY].iatoms;
903 /* HarmonicBondForce* ubBondForce = new HarmonicBondForce(); */
904 /* HarmonicAngleForce* ubAngleForce = new HarmonicAngleForce(); */
905 /* sys->addForce(ubBondForce); */
906 /* sys->addForce(ubAngleForce); */
908 for (int i = 0; i < numUB; ++i)
910 int type = ubAtoms[offset++];
911 int atom1 = ubAtoms[offset++];
912 int atom2 = ubAtoms[offset++];
913 int atom3 = ubAtoms[offset++];
914 /* ubBondForce->addBond(atom1, atom3, */
915 bondForce->addBond(atom1, atom3,
916 idef.iparams[type].u_b.r13, idef.iparams[type].u_b.kUB);
917 /* ubAngleForce->addAngle(atom1, atom2, atom3, */
918 angleForce->addAngle(atom1, atom2, atom3,
919 idef.iparams[type].u_b.theta*M_PI/180.0, idef.iparams[type].u_b.ktheta);
922 /* Set proper dihedral terms */
923 const int* periodicAtoms = (int*) idef.il[F_PDIHS].iatoms;
924 PeriodicTorsionForce* periodicForce = new PeriodicTorsionForce();
925 sys->addForce(periodicForce);
927 for (int i = 0; i < numPeriodic; ++i)
929 int type = periodicAtoms[offset++];
930 int atom1 = periodicAtoms[offset++];
931 int atom2 = periodicAtoms[offset++];
932 int atom3 = periodicAtoms[offset++];
933 int atom4 = periodicAtoms[offset++];
934 periodicForce->addTorsion(atom1, atom2, atom3, atom4,
935 idef.iparams[type].pdihs.mult,
936 idef.iparams[type].pdihs.phiA*M_PI/180.0,
937 idef.iparams[type].pdihs.cpA);
940 /* Set improper dihedral terms that are represented by a periodic function (as in AMBER FF) */
941 const int* periodicImproperAtoms = (int*) idef.il[F_PIDIHS].iatoms;
942 /* PeriodicTorsionForce* periodicImproperForce = new PeriodicTorsionForce(); */
943 /* sys->addForce(periodicImproperForce); */
945 for (int i = 0; i < numPeriodicImproper; ++i)
947 int type = periodicImproperAtoms[offset++];
948 int atom1 = periodicImproperAtoms[offset++];
949 int atom2 = periodicImproperAtoms[offset++];
950 int atom3 = periodicImproperAtoms[offset++];
951 int atom4 = periodicImproperAtoms[offset++];
952 /* periodicImproperForce->addTorsion(atom1, atom2, atom3, atom4, */
953 periodicForce->addTorsion(atom1, atom2, atom3, atom4,
954 idef.iparams[type].pdihs.mult,
955 idef.iparams[type].pdihs.phiA*M_PI/180.0,
956 idef.iparams[type].pdihs.cpA);
959 /* Ryckaert-Bellemans dihedrals */
960 const int* rbAtoms = (int*) idef.il[F_RBDIHS].iatoms;
961 RBTorsionForce* rbForce = new RBTorsionForce();
962 sys->addForce(rbForce);
964 for (int i = 0; i < numRB; ++i)
966 int type = rbAtoms[offset++];
967 int atom1 = rbAtoms[offset++];
968 int atom2 = rbAtoms[offset++];
969 int atom3 = rbAtoms[offset++];
970 int atom4 = rbAtoms[offset++];
971 rbForce->addTorsion(atom1, atom2, atom3, atom4,
972 idef.iparams[type].rbdihs.rbcA[0], idef.iparams[type].rbdihs.rbcA[1],
973 idef.iparams[type].rbdihs.rbcA[2], idef.iparams[type].rbdihs.rbcA[3],
974 idef.iparams[type].rbdihs.rbcA[4], idef.iparams[type].rbdihs.rbcA[5]);
977 /* Set improper dihedral terms (as in CHARMM FF) */
978 const int* improperDihAtoms = (int*) idef.il[F_IDIHS].iatoms;
979 CustomTorsionForce* improperDihForce = new CustomTorsionForce("2.0*k*asin(sin((theta-theta0)/2))^2");
980 sys->addForce(improperDihForce);
981 improperDihForce->addPerTorsionParameter("k");
982 improperDihForce->addPerTorsionParameter("theta0");
983 vector<double> improperDihParameters(2);
985 for (int i = 0; i < numImproperDih; ++i)
987 int type = improperDihAtoms[offset++];
988 int atom1 = improperDihAtoms[offset++];
989 int atom2 = improperDihAtoms[offset++];
990 int atom3 = improperDihAtoms[offset++];
991 int atom4 = improperDihAtoms[offset++];
992 improperDihParameters[0] = idef.iparams[type].harmonic.krA;
993 improperDihParameters[1] = idef.iparams[type].harmonic.rA*M_PI/180.0;
994 improperDihForce->addTorsion(atom1, atom2, atom3, atom4,
995 improperDihParameters);
998 /* Set nonbonded parameters and masses. */
999 int ntypes = fr->ntype;
1000 int* types = mdatoms->typeA;
1001 real* nbfp = fr->nbfp;
1002 real* charges = mdatoms->chargeA;
1003 real* masses = mdatoms->massT;
1004 NonbondedForce* nonbondedForce = new NonbondedForce();
1005 sys->addForce(nonbondedForce);
1010 if (ir->rcoulomb == 0)
1012 nonbondedForce->setNonbondedMethod(NonbondedForce::NoCutoff);
1016 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
1020 switch (ir->coulombtype)
1027 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
1031 nonbondedForce->setNonbondedMethod(NonbondedForce::Ewald);
1035 nonbondedForce->setNonbondedMethod(NonbondedForce::PME);
1039 gmx_fatal(FARGS,"Internal error: you should not see this message, it means that the"
1040 "electrosatics option check failed. Please report this error!");
1042 sys->setDefaultPeriodicBoxVectors(Vec3(state->box[0][0], 0, 0),
1043 Vec3(0, state->box[1][1], 0), Vec3(0, 0, state->box[2][2]));
1044 nonbondedForce->setCutoffDistance(ir->rcoulomb);
1048 gmx_fatal(FARGS,"OpenMM supports only full periodic boundary conditions "
1049 "(pbc = xyz), or none (pbc = no).");
1053 /* Fix for PME and Ewald error tolerance
1055 * OpenMM uses approximate formulas to calculate the Ewald parameter:
1056 * alpha = (1.0/cutoff)*sqrt(-log(2.0*tolerlance));
1057 * and the grid spacing for PME:
1058 * gridX = ceil(2*alpha*box[0][0]/3*(pow(tol, 0.2)))
1059 * gridY = ceil(2*alpha*box[1][1]/3*(pow(tol, 0.2)));
1060 * gridZ = ceil(2*alpha*box[2][2]/3*(pow(tol, 0.2)));
1063 * If the default ewald_rtol=1e-5 is used we silently adjust the value to the
1064 * OpenMM default of 5e-4 otherwise a warning is issued about the action taken.
1067 double corr_ewald_rtol = 50.0 * ir->ewald_rtol;
1068 if ((ir->ePBC == epbcXYZ) &&
1069 (ir->coulombtype == eelEWALD || ir->coulombtype == eelPME))
1073 fprintf(debug, ">> ewald_rtol = %e (corrected = %e) \n",
1074 ir->ewald_rtol, corr_ewald_rtol);
1077 if (fabs(ir->ewald_rtol - 1e-5) > 1e-10)
1079 gmx_warning("OpenMM uses the ewald_rtol parameter with approximate formulas "
1080 "to calculate the alpha and grid spacing parameters of the Ewald "
1081 "and PME methods. This tolerance need to be corrected in order to get "
1082 "settings close to the ones used in GROMACS. Although the internal correction "
1083 "should work for any reasonable value of ewald_rtol, using values other than "
1084 "the default 1e-5 might cause incorrect behavior.");
1086 if (corr_ewald_rtol > 1)
1088 gmx_fatal(FARGS, "The ewald_rtol accuracy term is >1 after the "
1089 "adjustment for OpenMM (%e)", corr_ewald_rtol);
1092 nonbondedForce->setEwaldErrorTolerance(corr_ewald_rtol);
1095 for (int i = 0; i < numAtoms; ++i)
1097 double c12 = nbfp[types[i]*2*ntypes+types[i]*2+1];
1098 double c6 = nbfp[types[i]*2*ntypes+types[i]*2];
1099 double sigma=0.0, epsilon=0.0;
1100 convert_c_12_6(c12, c6, &sigma, &epsilon);
1101 nonbondedForce->addParticle(charges[i], sigma, epsilon);
1102 sys->addParticle(masses[i]);
1105 // Build a table of all exclusions.
1106 vector<set<int> > exclusions(numAtoms);
1107 for (int i = 0; i < numAtoms; i++)
1109 int start = top->excls.index[i];
1110 int end = top->excls.index[i+1];
1111 for (int j = start; j < end; j++)
1112 exclusions[i].insert(top->excls.a[j]);
1115 // Record the 1-4 interactions, and remove them from the list of exclusions.
1116 const int* nb14Atoms = (int*) idef.il[F_LJ14].iatoms;
1118 for (int i = 0; i < num14; ++i)
1120 int type = nb14Atoms[offset++];
1121 int atom1 = nb14Atoms[offset++];
1122 int atom2 = nb14Atoms[offset++];
1123 double sigma=0, epsilon=0;
1124 convert_c_12_6(idef.iparams[type].lj14.c12A,
1125 idef.iparams[type].lj14.c6A,
1127 nonbondedForce->addException(atom1, atom2,
1128 fr->fudgeQQ*charges[atom1]*charges[atom2], sigma, epsilon);
1129 exclusions[atom1].erase(atom2);
1130 exclusions[atom2].erase(atom1);
1133 // Record exclusions.
1134 for (int i = 0; i < numAtoms; i++)
1136 for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
1140 nonbondedForce->addException(i, *iter, 0.0, 1.0, 0.0);
1145 // Add GBSA if needed.
1146 if (ir->implicit_solvent == eisGBSA)
1148 gmx_warning("The OBC scale factors alpha, beta and gamma are hardcoded in OpenMM with the default Gromacs values.");
1149 t_atoms atoms = gmx_mtop_global_atoms(top_global);
1150 GBSAOBCForce* gbsa = new GBSAOBCForce();
1152 sys->addForce(gbsa);
1153 gbsa->setSoluteDielectric(ir->epsilon_r);
1154 gbsa->setSolventDielectric(ir->gb_epsilon_solvent);
1155 gbsa->setCutoffDistance(nonbondedForce->getCutoffDistance());
1156 if (nonbondedForce->getNonbondedMethod() == NonbondedForce::NoCutoff)
1157 gbsa->setNonbondedMethod(GBSAOBCForce::NoCutoff);
1158 else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic)
1159 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
1160 else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffPeriodic)
1161 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
1163 gmx_fatal(FARGS,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
1165 for (int i = 0; i < numAtoms; ++i)
1167 gbsa->addParticle(charges[i],
1168 top_global->atomtypes.gb_radius[atoms.atom[i].type],
1169 top_global->atomtypes.S_hct[atoms.atom[i].type]);
1171 free_t_atoms(&atoms, FALSE);
1175 const int* constraintAtoms = (int*) idef.il[F_CONSTR].iatoms;
1177 for (int i = 0; i < numConstraints; ++i)
1179 int type = constraintAtoms[offset++];
1180 int atom1 = constraintAtoms[offset++];
1181 int atom2 = constraintAtoms[offset++];
1182 sys->addConstraint(atom1, atom2, idef.iparams[type].constr.dA);
1184 const int* settleAtoms = (int*) idef.il[F_SETTLE].iatoms;
1186 for (int i = 0; i < numSettle; ++i)
1188 int type = settleAtoms[offset++];
1189 int oxygen = settleAtoms[offset++];
1190 sys->addConstraint(oxygen, oxygen+1, idef.iparams[type].settle.doh);
1191 sys->addConstraint(oxygen, oxygen+2, idef.iparams[type].settle.doh);
1192 sys->addConstraint(oxygen+1, oxygen+2, idef.iparams[type].settle.dhh);
1195 // Create an integrator for simulating the system.
1196 double friction = (ir->opts.tau_t[0] == 0.0 ? 0.0 : 1.0/ir->opts.tau_t[0]);
1200 integ = new BrownianIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1201 static_cast<BrownianIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed);
1203 else if (EI_SD(ir->eI))
1205 integ = new LangevinIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1206 static_cast<LangevinIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed);
1210 integ = new VerletIntegrator(ir->delta_t);
1211 if ( ir->etc != etcNO)
1213 AndersenThermostat* thermostat = new AndersenThermostat(ir->opts.ref_t[0], friction);
1214 sys->addForce(thermostat);
1218 // Add pressure coupling
1219 if (ir->epc != epcNO)
1221 // convert gromacs pressure tensor to a scalar
1222 double pressure = (ir->ref_p[0][0] + ir->ref_p[1][1] + ir->ref_p[2][2]) / 3.0;
1223 int frequency = int(ir->tau_p / ir->delta_t); // update frequency in time steps
1224 if (frequency < 1) frequency = 1;
1225 double temperature = ir->opts.ref_t[0]; // in kelvin
1226 sys->addForce(new MonteCarloBarostat(pressure, temperature, frequency));
1229 integ->setConstraintTolerance(ir->shake_tol);
1231 // Create a context and initialize it.
1232 Context* context = NULL;
1235 OpenMM could automatically select the "best" GPU, however we're not't
1236 going to let it do that for now, as the current algorithm is very rudimentary
1237 and we anyway support only CUDA.
1238 if (platformOptStr == NULL || platformOptStr == "")
1240 context = new Context(*sys, *integ);
1245 /* which platform should we use */
1246 for (int i = 0; i < (int)Platform::getNumPlatforms() && context == NULL; i++)
1248 if (isStringEqNCase(opt->getOptionValue("platform"), Platform::getPlatform(i).getName()))
1250 Platform& platform = Platform::getPlatform(i);
1251 // set standard properties
1252 platform.setPropertyDefaultValue("CudaDevice", opt->getOptionValue("deviceid"));
1253 // TODO add extra properties
1254 context = new Context(*sys, *integ, platform);
1257 if (context == NULL)
1259 gmx_fatal(FARGS, "The requested platform \"%s\" could not be found.",
1260 opt->getOptionValue("platform").c_str());
1264 Platform& platform = context->getPlatform();
1265 fprintf(fplog, "Gromacs will use the OpenMM platform: %s\n", platform.getName().c_str());
1267 const vector<string>& properties = platform.getPropertyNames();
1270 for (int i = 0; i < (int)properties.size(); i++)
1272 fprintf(debug, ">> %s: %s\n", properties[i].c_str(),
1273 platform.getPropertyValue(*context, properties[i]).c_str());
1278 if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1281 if (!from_string<int>(tmp, platform.getPropertyValue(*context, "CudaDevice"), std::dec))
1283 gmx_fatal(FARGS, "Internal error: couldn't determine the device selected by OpenMM");
1287 /* For now this is just to double-check if OpenMM selected the GPU we wanted,
1288 but when we'll let OpenMM select the GPU automatically, it will query the deviceId.
1292 gmx_fatal(FARGS, "Internal error: OpenMM is using device #%d"
1293 "while initialized for device #%d", tmp, devId);
1296 /* check GPU compatibility */
1297 char gpuname[STRLEN];
1298 devId = atoi(opt->getOptionValue("deviceid").c_str());
1299 if (!is_supported_cuda_gpu(-1, gpuname))
1301 if (!gmx_strcasecmp(opt->getOptionValue("force-device").c_str(), "yes"))
1303 sprintf(warn_buf, "Non-supported GPU selected (#%d, %s), forced continuing."
1304 "Note, that the simulation can be slow or it migth even crash.",
1306 fprintf(fplog, "%s\n", warn_buf);
1307 gmx_warning(warn_buf);
1311 gmx_fatal(FARGS, "The selected GPU (#%d, %s) is not supported by Gromacs! "
1312 "Most probably you have a low-end GPU which would not perform well, "
1313 "or new hardware that has not been tested with the current release. "
1314 "If you still want to try using the device, use the force-device=yes option.",
1320 fprintf(fplog, "Gromacs will run on the GPU #%d (%s).\n", devId, gpuname);
1325 if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1327 /* pre-simulation memtest */
1328 runMemtest(fplog, -1, "Pre", opt);
1331 vector<Vec3> pos(numAtoms);
1332 vector<Vec3> vel(numAtoms);
1333 for (int i = 0; i < numAtoms; ++i)
1335 pos[i] = Vec3(state->x[i][0], state->x[i][1], state->x[i][2]);
1336 vel[i] = Vec3(state->v[i][0], state->v[i][1], state->v[i][2]);
1338 context->setPositions(pos);
1339 context->setVelocities(vel);
1341 // Return a structure containing the system, integrator, and context.
1342 OpenMMData* data = new OpenMMData();
1344 data->integrator = integ;
1345 data->context = context;
1346 data->removeCM = (ir->nstcomm > 0);
1347 data->platformOpt = opt;
1350 catch (std::exception& e)
1352 gmx_fatal(FARGS, "OpenMM exception caught while initializating: %s", e.what());
1354 return NULL; /* just to avoid warnings */
1358 * \brief Integrate one step.
1360 * \param[in] data OpenMMData object created by openmm_init().
1362 void openmm_take_one_step(void* data)
1364 // static int step = 0; printf("----> taking step #%d\n", step++);
1367 static_cast<OpenMMData*>(data)->integrator->step(1);
1369 catch (std::exception& e)
1371 gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1376 * \brief Integrate n steps.
1378 * \param[in] data OpenMMData object created by openmm_init().
1380 void openmm_take_steps(void* data, int nstep)
1384 static_cast<OpenMMData*>(data)->integrator->step(nstep);
1386 catch (std::exception& e)
1388 gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1393 * \brief Clean up the data structures cretead for OpenMM.
1395 * \param[in] log Log file pointer.
1396 * \param[in] data OpenMMData object created by openmm_init().
1398 void openmm_cleanup(FILE* fplog, void* data)
1400 OpenMMData* d = static_cast<OpenMMData*>(data);
1402 if (isStringEqNCase(d->platformOpt->getOptionValue("platform"), "CUDA"))
1404 /* post-simulation memtest */
1405 runMemtest(fplog, -1, "Post", d->platformOpt);
1408 delete d->integrator;
1410 delete d->platformOpt;
1415 * \brief Copy the current state information from OpenMM into the Gromacs data structures.
1417 * This function results in the requested proprties to be copied from the
1418 * GPU to host. As this represents a bottleneck, the frequency of pulling data
1419 * should be minimized.
1421 * \param[in] data OpenMMData object created by openmm_init().
1422 * \param[out] time Simulation time for which the state was created.
1423 * \param[out] state State of the system: coordinates and velocities.
1424 * \param[out] f Forces.
1425 * \param[out] enerd Energies.
1426 * \param[in] includePos True if coordinates are requested.
1427 * \param[in] includeVel True if velocities are requested.
1428 * \param[in] includeForce True if forces are requested.
1429 * \param[in] includeEnergy True if energies are requested.
1431 void openmm_copy_state(void *data,
1432 t_state *state, double *time,
1433 rvec f[], gmx_enerdata_t *enerd,
1434 gmx_bool includePos, gmx_bool includeVel, gmx_bool includeForce, gmx_bool includeEnergy)
1438 types += State::Positions;
1440 types += State::Velocities;
1442 types += State::Forces;
1444 types += State::Energy;
1449 State currentState = static_cast<OpenMMData*>(data)->context->getState(types);
1450 int numAtoms = static_cast<OpenMMData*>(data)->system->getNumParticles();
1453 for (int i = 0; i < numAtoms; i++)
1455 Vec3 x = currentState.getPositions()[i];
1456 state->x[i][0] = x[0];
1457 state->x[i][1] = x[1];
1458 state->x[i][2] = x[2];
1463 for (int i = 0; i < numAtoms; i++)
1465 Vec3 v = currentState.getVelocities()[i];
1466 state->v[i][0] = v[0];
1467 state->v[i][1] = v[1];
1468 state->v[i][2] = v[2];
1473 for (int i = 0; i < numAtoms; i++)
1475 Vec3 force = currentState.getForces()[i];
1483 int numConstraints = static_cast<OpenMMData*>(data)->system->getNumConstraints();
1484 int dof = 3*numAtoms-numConstraints;
1485 if (static_cast<OpenMMData*>(data)->removeCM)
1487 enerd->term[F_EPOT] = currentState.getPotentialEnergy();
1488 enerd->term[F_EKIN] = currentState.getKineticEnergy();
1489 enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
1490 enerd->term[F_TEMP] = 2.0*enerd->term[F_EKIN]/dof/BOLTZ;
1492 *time = currentState.getTime();
1494 catch (std::exception& e)
1496 gmx_fatal(FARGS, "OpenMM exception caught while retrieving state information: %s", e.what());