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
56 #include "gmx_fatal.h"
61 #include "gmx_gpu_utils.h"
62 #include "mtop_util.h"
65 #include "openmm_wrapper.h"
67 using namespace OpenMM
;
70 #define MEM_ERR_MSG(str) \
71 "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
72 "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
73 "overclocked and that the device is properly cooled.\n", (str)
77 * \brief Convert string to integer type.
78 * \param[in] s String to convert from.
79 * \param[in] f Basefield format flag that takes any of the following I/O
80 * manipulators: dec, hex, oct.
81 * \param[out] t Destination variable to convert to.
84 static bool from_string(T
& t
, const string
& s
, ios_base
& (*f
)(ios_base
&))
87 return !(iss
>> f
>> t
).fail();
91 * \brief Split string around a given delimiter.
92 * \param[in] s String to split.
93 * \param[in] delim Delimiter character.
94 * \returns Vector of strings found in \p s.
96 static vector
<string
> split(const string
&s
, char delim
)
101 while (getline(ss
, item
, delim
))
103 if (item
.length() != 0)
104 elems
.push_back(item
);
110 * \brief Split a string of the form "option=value" into "option" and "value" strings.
111 * This string corresponds to one option and the associated value from the option list
112 * in the mdrun -device argument.
114 * \param[in] s A string containing an "option=value" pair that needs to be split up.
115 * \param[out] opt The name of the option.
116 * \param[out] val Value of the option.
118 static void splitOptionValue(const string
&s
, string
&opt
, string
&val
)
120 size_t eqPos
= s
.find('=');
121 if (eqPos
!= string::npos
)
123 opt
= s
.substr(0, eqPos
);
124 if (eqPos
!= s
.length()) val
= s
.substr(eqPos
+1);
129 * \brief Compare two strings ignoring case.
130 * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
131 * \param[in] s1 String.
132 * \param[in] s2 String.
133 * \returns Similarly to the C function strncasecmp(), the return value is an
134 integer less than, equal to, or greater than 0 if \p s1 less than,
135 identical to, or greater than \p s2.
137 static bool isStringEqNCase(const string s1
, const string s2
)
139 return (gmx_strncasecmp(s1
.c_str(), s2
.c_str(), max(s1
.length(), s2
.length())) == 0);
143 * \brief Convert string to upper case.
145 * \param[in] s String to convert to uppercase.
146 * \returns The given string converted to uppercase.
148 static string
toUpper(const string
&s
)
151 std::transform(stmp
.begin(), stmp
.end(), stmp
.begin(), static_cast < int(*)(int) > (toupper
));
156 \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms,
157 GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
158 GmxOpenMMPlatformOptions#force_dev. */
160 #define SIZEOF_PLATFORMS 1 // 2
161 #define SIZEOF_MEMTESTS 3
162 #define SIZEOF_DEVICEIDS 1
163 #define SIZEOF_FORCE_DEV 2
166 /*! Possible platform options in the mdrun -device option. */
167 static const char *devOptStrings
[] = { "platform", "deviceid", "memtest", "force-device" };
169 /*! Enumerated platform options in the mdrun -device option. */
179 * \brief Class to extract and manage the platform options in the mdrun -device option.
182 class GmxOpenMMPlatformOptions
185 GmxOpenMMPlatformOptions(const char *opt
);
186 ~GmxOpenMMPlatformOptions() { options
.clear(); }
187 string
getOptionValue(const string
&opt
);
188 void remOption(const string
&opt
);
190 void setOption(const string
&opt
, const string
&val
);
192 map
<string
, string
> options
; /*!< Data structure to store the option (name, value) pairs. */
194 static const char * const platforms
[SIZEOF_PLATFORMS
]; /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
195 static const char * const memtests
[SIZEOF_MEMTESTS
]; /*!< Available types of memory tests, also valid
196 any positive integer >=15; size #SIZEOF_MEMTESTS */
197 static const char * const deviceid
[SIZEOF_DEVICEIDS
]; /*!< Possible values for deviceid option;
198 also valid any positive integer; size #SIZEOF_DEVICEIDS */
199 static const char * const force_dev
[SIZEOF_FORCE_DEV
]; /*!< Possible values for for force-device option;
200 size #SIZEOF_FORCE_DEV */
203 const char * const GmxOpenMMPlatformOptions::platforms
[SIZEOF_PLATFORMS
]
205 //= { "Reference", "CUDA" /*,"OpenCL"*/ };
206 const char * const GmxOpenMMPlatformOptions::memtests
[SIZEOF_MEMTESTS
]
207 = { "15", "full", "off" };
208 const char * const GmxOpenMMPlatformOptions::deviceid
[SIZEOF_DEVICEIDS
]
210 const char * const GmxOpenMMPlatformOptions::force_dev
[SIZEOF_FORCE_DEV
]
215 * Takes the option list, parses it, checks the options and their values for validity.
216 * When certain options are not provided by the user, as default value the first item
217 * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms,
218 * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid,
219 * GmxOpenMMPlatformOptions#force_dev).
220 * \param[in] optionString Option string part of the mdrun -deviceoption parameter.
222 GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString
)
224 // set default values
225 setOption("platform", platforms
[0]);
226 setOption("memtest", memtests
[0]);
227 setOption("deviceid", deviceid
[0]);
228 setOption("force-device", force_dev
[0]);
230 string
opt(optionString
);
232 // remove all whitespaces
233 opt
.erase(remove_if(opt
.begin(), opt
.end(), ::isspace
), opt
.end());
234 // tokenize around ","-s
235 vector
<string
> tokens
= split(opt
, ',');
237 for (vector
<string
>::iterator it
= tokens
.begin(); it
!= tokens
.end(); ++it
)
239 string opt
= "", val
= "";
240 splitOptionValue(*it
, opt
, val
);
242 if (isStringEqNCase(opt
, "platform"))
244 /* no check, this will fail if platform does not exist when we try to set it */
249 if (isStringEqNCase(opt
, "memtest"))
251 /* the value has to be an integer >15(s) or "full" OR "off" */
252 if (!isStringEqNCase(val
, "full") && !isStringEqNCase(val
, "off"))
255 if (!from_string
<int>(secs
, val
, std::dec
))
257 gmx_fatal(FARGS
, "Invalid value for option memtest option: \"%s\"!", val
.c_str());
261 gmx_fatal(FARGS
, "Incorrect value for memtest option (%d). "
262 "Memtest needs to run for at least 15s!", secs
);
269 if (isStringEqNCase(opt
, "deviceid"))
272 if (!from_string
<int>(id
, val
, std::dec
) )
274 gmx_fatal(FARGS
, "Invalid device id: \"%s\"!", val
.c_str());
280 if (isStringEqNCase(opt
, "force-device"))
283 if (!isStringEqNCase(val
, "yes") && !isStringEqNCase(val
, "no"))
285 gmx_fatal(FARGS
, "Invalid OpenMM force option: \"%s\"!", val
.c_str());
291 // if we got till here something went wrong
292 gmx_fatal(FARGS
, "Invalid OpenMM platform option: \"%s\"!", (*it
).c_str());
298 * \brief Returns the value of an option.
299 * \param[in] opt Name of the option.
301 string
GmxOpenMMPlatformOptions::getOptionValue(const string
&opt
)
303 if (options
.find(toUpper(opt
)) != options
.end())
305 return options
[toUpper(opt
)];
314 * \brief Setter function - private, only used from contructor.
315 * \param[in] opt Name of the option.
316 * \param[in] val Value for the option.
318 void GmxOpenMMPlatformOptions::setOption(const string
&opt
, const string
&val
)
320 options
[toUpper(opt
)] = val
;
324 * \brief Removes an option with its value from the map structure. If the option
325 * does not exist, returns without any action.
326 * \param[in] opt Name of the option.
328 void GmxOpenMMPlatformOptions::remOption(const string
&opt
)
330 options
.erase(toUpper(opt
));
335 * \brief Container for OpenMM related data structures that represent the bridge
336 * between the Gromacs data-structures and the OpenMM library and is but it's
337 * only passed through the API functions as void to disable direct access.
342 System
* system
; /*! The system to simulate. */
343 Context
* context
; /*! The OpenMM context in which the simulation is carried out. */
344 Integrator
* integrator
; /*! The integrator used in the simulation. */
345 bool removeCM
; /*! If \true remove venter of motion, false otherwise. */
346 GmxOpenMMPlatformOptions
*platformOpt
; /*! Platform options. */
350 * \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
351 * \param[in] fplog Pointer to gromacs log file.
352 * \param[in] devId Device id of the GPU to run the test on. TODO: this can be removed!
353 * \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in
354 * stdout messages/log between memtest carried out before and after simulation.
355 * \param[in] opt Pointer to platform options object.
357 static void runMemtest(FILE* fplog
, int devId
, const char* pre_post
, GmxOpenMMPlatformOptions
*opt
)
360 char warn_buf
[STRLEN
];
364 const char * test_type
= opt
->getOptionValue("memtest").c_str();
365 if (!gmx_strcasecmp(test_type
, "off"))
371 if (!gmx_strcasecmp(test_type
, "full"))
377 from_string
<int>(which_test
, test_type
, std::dec
);
383 case 0: /* no memtest */
384 sprintf(warn_buf
, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
385 "incorrect results!", pre_post
);
386 fprintf(fplog
, "%s\n", warn_buf
);
387 gmx_warning(warn_buf
);
390 case 1: /* quick memtest */
391 fprintf(fplog
, "%s-simulation %s GPU memtest in progress...\n", pre_post
, test_type
);
392 fprintf(stdout
, "\n%s-simulation %s GPU memtest in progress...", pre_post
, test_type
);
395 if (do_quick_memtest(-1) != 0)
397 gmx_fatal(FARGS
,MEM_ERR_MSG(pre_post
));
401 fprintf(fplog
, "Memory test completed without errors.\n");
402 fprintf(stdout
, "done, no errors detected\n");
406 case 2: /* full memtest */
407 fprintf(fplog
, "%s-simulation %s memtest in progress...\n", pre_post
, test_type
);
408 fprintf(stdout
, "\n%s-simulation %s memtest in progress...", pre_post
, test_type
);
411 if (do_full_memtest(-1) != 0)
413 gmx_fatal(FARGS
, MEM_ERR_MSG(pre_post
) );
418 fprintf(fplog
, "Memory test completed without errors.\n");
419 fprintf(stdout
, "done, no errors detected\n");
423 default: /* timed memtest */
424 fprintf(fplog
, "%s-simulation memtest for ~%ds in progress...\n", pre_post
, which_test
);
425 fprintf(stdout
, "\n%s-simulation memtest for ~%ds in progress...", pre_post
, which_test
);
428 if (do_timed_memtest(-1, which_test
) != 0)
430 gmx_fatal(FARGS
, MEM_ERR_MSG(pre_post
));
435 fprintf(fplog
, "Memory test completed without errors.\n");
436 fprintf(stdout
, "done, no errors detected.\n");
444 * \brief Does gromacs option checking.
446 * Checks the gromacs mdp options for features unsupported in OpenMM, case in which
447 * interrupts the execution. It also warns the user about pecularities of OpenMM
449 * \param[in] ir Gromacs structure for input options, \see ::t_inputrec
450 * \param[in] top Gromacs local topology, \see ::gmx_localtop_t
451 * \param[in] state Gromacs state structure \see ::t_state
453 static void checkGmxOptions(t_inputrec
*ir
, gmx_localtop_t
*top
, t_state
*state
)
455 char warn_buf
[STRLEN
];
457 /* Abort if unsupported critical options are present */
462 gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
465 if ( (ir
->eI
!= eiMD
) &&
467 (ir
->eI
!= eiVVAK
) &&
472 gmx_fatal(FARGS
, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
476 if ( (ir
->coulombtype
!= eelPME
) &&
477 (ir
->coulombtype
!= eelRF
) &&
478 (ir
->coulombtype
!= eelEWALD
) &&
480 ( !(ir
->coulombtype
== eelCUT
&& ir
->rcoulomb
== 0 && ir
->rvdw
== 0)) )
482 gmx_fatal(FARGS
,"OpenMM supports only the following methods for electrostatics: "
483 "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
486 if (ir
->etc
!= etcNO
&&
491 gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
494 if (ir
->opts
.ngtc
> 1)
495 gmx_fatal(FARGS
,"OpenMM does not support multiple temperature coupling groups.");
497 if (ir
->epc
!= etcNO
)
498 gmx_fatal(FARGS
,"OpenMM does not support pressure coupling.");
500 if (ir
->opts
.annealing
[0])
501 gmx_fatal(FARGS
,"OpenMM does not support simulated annealing.");
503 if (ir
->eConstrAlg
!= econtSHAKE
)
504 gmx_warning("OpenMM provides contraints as a combination "
505 "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
506 "by the \"shake_tol\" option.");
509 gmx_fatal(FARGS
,"OpenMM does not support walls.");
511 if (ir
->ePull
!= epullNO
)
512 gmx_fatal(FARGS
,"OpenMM does not support pulling.");
514 /* check for restraints */
516 for (i
= 0; i
< F_EPOT
; i
++)
525 top
->idef
.il
[i
].nr
> 0)
527 /* TODO fix the message */
528 gmx_fatal(FARGS
, "OpenMM does not support (some) of the provided restaint(s).");
532 if (ir
->efep
!= efepNO
)
533 gmx_fatal(FARGS
,"OpenMM does not support free energy calculations.");
535 if (ir
->opts
.ngacc
> 1)
536 gmx_fatal(FARGS
,"OpenMM does not support non-equilibrium MD (accelerated groups).");
538 if (IR_ELEC_FIELD(*ir
))
539 gmx_fatal(FARGS
,"OpenMM does not support electric fields.");
542 gmx_fatal(FARGS
,"OpenMM does not support QMMM calculations.");
544 if (ir
->rcoulomb
!= ir
->rvdw
)
545 gmx_fatal(FARGS
,"OpenMM uses a single cutoff for both Coulomb "
546 "and VdW interactions. Please set rcoulomb equal to rvdw.");
548 if (EEL_FULL(ir
->coulombtype
))
550 if (ir
->ewald_geometry
== eewg3DC
)
551 gmx_fatal(FARGS
,"OpenMM supports only Ewald 3D geometry.");
552 if (ir
->epsilon_surface
!= 0)
553 gmx_fatal(FARGS
,"OpenMM does not support dipole correction in Ewald summation.");
556 if (TRICLINIC(state
->box
))
558 gmx_fatal(FARGS
,"OpenMM does not support triclinic unit cells.");
565 * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
570 * \param[out] epsilon
572 static void* convert_c_12_6(double c12
, double c6
, double *sigma
, double *epsilon
)
574 if (c12
== 0 && c6
== 0)
579 else if (c12
> 0 && c6
> 0)
581 *epsilon
= (c6
*c6
)/(4.0*c12
);
582 *sigma
= pow(c12
/c6
, 1.0/6.0);
586 gmx_fatal(FARGS
,"OpenMM does only supports c6 > 0 and c12 > 0 or both 0.");
591 * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to
594 * Various gromacs data structures are passed that contain the parameters, state and
595 * other porperties of the system to simulate. These serve as input for initializing
596 * OpenMM. Besides, a set of misc action are taken:
597 * - OpenMM plugins are loaded;
598 * - platform options in \p platformOptStr are parsed and checked;
599 * - Gromacs parameters are checked for OpenMM support and consistency;
600 * - after the OpenMM is initialized memtest executed in the same GPU context.
602 * \param[in] fplog Gromacs log file handler.
603 * \param[in] platformOptStr Platform option string.
604 * \param[in] ir The Gromacs input parameters, see ::t_inputrec
605 * \param[in] top_global TODO Gromacs whole system toppology, \see ::gmx_mtop_t
606 * \param[in] top TODO Gromacs node local topology, \see gmx_localtop_t
607 * \param[in] mdatoms TODO \see ::t_mdatoms
608 * \param[in] fr TODO \see ::t_forcerec
609 * \param[in] state TODO \see ::t_state
612 void* openmm_init(FILE *fplog
, const char *platformOptStr
,
614 gmx_mtop_t
*top_global
, gmx_localtop_t
*top
,
615 t_mdatoms
*mdatoms
, t_forcerec
*fr
, t_state
*state
)
618 char warn_buf
[STRLEN
];
619 static bool hasLoadedPlugins
= false;
620 string usedPluginDir
;
625 if (!hasLoadedPlugins
)
627 vector
<string
> loadedPlugins
;
628 /* Look for OpenMM plugins at various locations (listed in order of priority):
629 - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
630 - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
631 - at the default location assumed by OpenMM
634 char *pluginDir
= getenv("OPENMM_PLUGIN_DIR");
636 /* no env var or empty */
637 if (pluginDir
!= NULL
&& *pluginDir
!= '\0')
639 loadedPlugins
= Platform::loadPluginsFromDirectory(pluginDir
);
640 if (loadedPlugins
.size() > 0)
642 hasLoadedPlugins
= true;
643 usedPluginDir
= pluginDir
;
647 gmx_fatal(FARGS
, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
648 "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!",
653 /* macro set at build time */
654 #ifdef OPENMM_PLUGIN_DIR
655 if (!hasLoadedPlugins
)
657 loadedPlugins
= Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR
);
658 if (loadedPlugins
.size() > 0)
660 hasLoadedPlugins
= true;
661 usedPluginDir
= OPENMM_PLUGIN_DIR
;
665 /* default loocation */
666 if (!hasLoadedPlugins
)
668 loadedPlugins
= Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
669 if (loadedPlugins
.size() > 0)
671 hasLoadedPlugins
= true;
672 usedPluginDir
= Platform::getDefaultPluginsDirectory();
676 /* if there are still no plugins loaded there won't be any */
677 if (!hasLoadedPlugins
)
679 gmx_fatal(FARGS
, "No OpenMM plugins were found! You can provide the"
680 " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir
);
683 fprintf(fplog
, "\nPlugins loaded from directory %s:\t", usedPluginDir
.c_str());
684 for (int i
= 0; i
< loadedPlugins
.size(); i
++)
686 fprintf(fplog
, "%s, ", loadedPlugins
[i
].c_str());
688 fprintf(fplog
, "\n");
691 /* parse option string */
692 GmxOpenMMPlatformOptions
*opt
= new GmxOpenMMPlatformOptions(platformOptStr
);
694 /* check wheter Gromacs options compatibility with OpenMM */
695 checkGmxOptions(ir
, top
, state
);
697 // Create the system.
698 const t_idef
& idef
= top
->idef
;
699 const int numAtoms
= top_global
->natoms
;
700 const int numConstraints
= idef
.il
[F_CONSTR
].nr
/3;
701 const int numSettle
= idef
.il
[F_SETTLE
].nr
/2;
702 const int numBonds
= idef
.il
[F_BONDS
].nr
/3;
703 const int numAngles
= idef
.il
[F_ANGLES
].nr
/4;
704 const int numPeriodic
= idef
.il
[F_PDIHS
].nr
/5;
705 const int numRB
= idef
.il
[F_RBDIHS
].nr
/5;
706 const int num14
= idef
.il
[F_LJ14
].nr
/3;
707 System
* sys
= new System();
709 sys
->addForce(new CMMotionRemover(ir
->nstcomm
));
711 // Set bonded force field terms.
712 const int* bondAtoms
= (int*) idef
.il
[F_BONDS
].iatoms
;
713 HarmonicBondForce
* bondForce
= new HarmonicBondForce();
714 sys
->addForce(bondForce
);
716 for (int i
= 0; i
< numBonds
; ++i
)
718 int type
= bondAtoms
[offset
++];
719 int atom1
= bondAtoms
[offset
++];
720 int atom2
= bondAtoms
[offset
++];
721 bondForce
->addBond(atom1
, atom2
,
722 idef
.iparams
[type
].harmonic
.rA
, idef
.iparams
[type
].harmonic
.krA
);
724 const int* angleAtoms
= (int*) idef
.il
[F_ANGLES
].iatoms
;
725 HarmonicAngleForce
* angleForce
= new HarmonicAngleForce();
726 sys
->addForce(angleForce
);
728 for (int i
= 0; i
< numAngles
; ++i
)
730 int type
= angleAtoms
[offset
++];
731 int atom1
= angleAtoms
[offset
++];
732 int atom2
= angleAtoms
[offset
++];
733 int atom3
= angleAtoms
[offset
++];
734 angleForce
->addAngle(atom1
, atom2
, atom3
,
735 idef
.iparams
[type
].harmonic
.rA
*M_PI
/180.0, idef
.iparams
[type
].harmonic
.krA
);
737 const int* periodicAtoms
= (int*) idef
.il
[F_PDIHS
].iatoms
;
738 PeriodicTorsionForce
* periodicForce
= new PeriodicTorsionForce();
739 sys
->addForce(periodicForce
);
741 for (int i
= 0; i
< numPeriodic
; ++i
)
743 int type
= periodicAtoms
[offset
++];
744 int atom1
= periodicAtoms
[offset
++];
745 int atom2
= periodicAtoms
[offset
++];
746 int atom3
= periodicAtoms
[offset
++];
747 int atom4
= periodicAtoms
[offset
++];
748 periodicForce
->addTorsion(atom1
, atom2
, atom3
, atom4
,
749 idef
.iparams
[type
].pdihs
.mult
,
750 idef
.iparams
[type
].pdihs
.phiA
*M_PI
/180.0,
751 idef
.iparams
[type
].pdihs
.cpA
);
753 const int* rbAtoms
= (int*) idef
.il
[F_RBDIHS
].iatoms
;
754 RBTorsionForce
* rbForce
= new RBTorsionForce();
755 sys
->addForce(rbForce
);
757 for (int i
= 0; i
< numRB
; ++i
)
759 int type
= rbAtoms
[offset
++];
760 int atom1
= rbAtoms
[offset
++];
761 int atom2
= rbAtoms
[offset
++];
762 int atom3
= rbAtoms
[offset
++];
763 int atom4
= rbAtoms
[offset
++];
764 rbForce
->addTorsion(atom1
, atom2
, atom3
, atom4
,
765 idef
.iparams
[type
].rbdihs
.rbcA
[0], idef
.iparams
[type
].rbdihs
.rbcA
[1],
766 idef
.iparams
[type
].rbdihs
.rbcA
[2], idef
.iparams
[type
].rbdihs
.rbcA
[3],
767 idef
.iparams
[type
].rbdihs
.rbcA
[4], idef
.iparams
[type
].rbdihs
.rbcA
[5]);
770 // Set nonbonded parameters and masses.
771 int ntypes
= fr
->ntype
;
772 int* types
= mdatoms
->typeA
;
773 real
* nbfp
= fr
->nbfp
;
774 real
* charges
= mdatoms
->chargeA
;
775 real
* masses
= mdatoms
->massT
;
776 NonbondedForce
* nonbondedForce
= new NonbondedForce();
777 sys
->addForce(nonbondedForce
);
782 if (ir
->rcoulomb
== 0)
784 nonbondedForce
->setNonbondedMethod(NonbondedForce::NoCutoff
);
788 nonbondedForce
->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic
);
792 switch (ir
->coulombtype
)
795 nonbondedForce
->setNonbondedMethod(NonbondedForce::CutoffPeriodic
);
799 nonbondedForce
->setNonbondedMethod(NonbondedForce::Ewald
);
803 nonbondedForce
->setNonbondedMethod(NonbondedForce::PME
);
807 gmx_fatal(FARGS
,"Internal error: you should not see this message, it that the"
808 "electrosatics option check failed. Please report this error!");
810 sys
->setPeriodicBoxVectors(Vec3(state
->box
[0][0], 0, 0),
811 Vec3(0, state
->box
[1][1], 0), Vec3(0, 0, state
->box
[2][2]));
812 nonbondedForce
->setCutoffDistance(ir
->rcoulomb
);
816 gmx_fatal(FARGS
,"OpenMM supports only full periodic boundary conditions "
817 "(pbc = xyz), or none (pbc = no).");
820 for (int i
= 0; i
< numAtoms
; ++i
)
822 double c12
= nbfp
[types
[i
]*2*ntypes
+types
[i
]*2+1];
823 double c6
= nbfp
[types
[i
]*2*ntypes
+types
[i
]*2];
824 double sigma
, epsilon
;
825 convert_c_12_6(c12
, c6
, &sigma
, &epsilon
);
826 nonbondedForce
->addParticle(charges
[i
], sigma
, epsilon
);
827 sys
->addParticle(masses
[i
]);
830 // Build a table of all exclusions.
831 vector
<set
<int> > exclusions(numAtoms
);
832 for (int i
= 0; i
< numAtoms
; i
++)
834 int start
= top
->excls
.index
[i
];
835 int end
= top
->excls
.index
[i
+1];
836 for (int j
= start
; j
< end
; j
++)
837 exclusions
[i
].insert(top
->excls
.a
[j
]);
840 // Record the 1-4 interactions, and remove them from the list of exclusions.
841 const int* nb14Atoms
= (int*) idef
.il
[F_LJ14
].iatoms
;
843 for (int i
= 0; i
< num14
; ++i
)
845 int type
= nb14Atoms
[offset
++];
846 int atom1
= nb14Atoms
[offset
++];
847 int atom2
= nb14Atoms
[offset
++];
848 double sigma
, epsilon
;
849 convert_c_12_6(idef
.iparams
[type
].lj14
.c12A
,
850 idef
.iparams
[type
].lj14
.c6A
,
852 nonbondedForce
->addException(atom1
, atom2
,
853 fr
->fudgeQQ
*charges
[atom1
]*charges
[atom2
], sigma
, epsilon
);
854 exclusions
[atom1
].erase(atom2
);
855 exclusions
[atom2
].erase(atom1
);
858 // Record exclusions.
859 for (int i
= 0; i
< numAtoms
; i
++)
861 for (set
<int>::const_iterator iter
= exclusions
[i
].begin(); iter
!= exclusions
[i
].end(); ++iter
)
865 nonbondedForce
->addException(i
, *iter
, 0.0, 1.0, 0.0);
870 // Add GBSA if needed.
871 if (ir
->implicit_solvent
== eisGBSA
)
873 t_atoms atoms
= gmx_mtop_global_atoms(top_global
);
874 GBSAOBCForce
* gbsa
= new GBSAOBCForce();
877 gbsa
->setSoluteDielectric(ir
->epsilon_r
);
878 gbsa
->setSolventDielectric(ir
->gb_epsilon_solvent
);
879 gbsa
->setCutoffDistance(nonbondedForce
->getCutoffDistance());
880 if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::NoCutoff
)
881 gbsa
->setNonbondedMethod(GBSAOBCForce::NoCutoff
);
882 else if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic
)
883 gbsa
->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic
);
884 else if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::CutoffPeriodic
)
885 gbsa
->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic
);
887 gmx_fatal(FARGS
,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
889 for (int i
= 0; i
< numAtoms
; ++i
)
891 gbsa
->addParticle(charges
[i
],
892 top_global
->atomtypes
.gb_radius
[atoms
.atom
[i
].type
],
893 top_global
->atomtypes
.S_hct
[atoms
.atom
[i
].type
]);
895 free_t_atoms(&atoms
, FALSE
);
899 const int* constraintAtoms
= (int*) idef
.il
[F_CONSTR
].iatoms
;
901 for (int i
= 0; i
< numConstraints
; ++i
)
903 int type
= constraintAtoms
[offset
++];
904 int atom1
= constraintAtoms
[offset
++];
905 int atom2
= constraintAtoms
[offset
++];
906 sys
->addConstraint(atom1
, atom2
, idef
.iparams
[type
].constr
.dA
);
908 const int* settleAtoms
= (int*) idef
.il
[F_SETTLE
].iatoms
;
910 for (int i
= 0; i
< numSettle
; ++i
)
912 int type
= settleAtoms
[offset
++];
913 int oxygen
= settleAtoms
[offset
++];
914 sys
->addConstraint(oxygen
, oxygen
+1, idef
.iparams
[type
].settle
.doh
);
915 sys
->addConstraint(oxygen
, oxygen
+2, idef
.iparams
[type
].settle
.doh
);
916 sys
->addConstraint(oxygen
+1, oxygen
+2, idef
.iparams
[type
].settle
.dhh
);
919 // Create an integrator for simulating the system.
920 double friction
= (ir
->opts
.tau_t
[0] == 0.0 ? 0.0 : 1.0/ir
->opts
.tau_t
[0]);
924 integ
= new BrownianIntegrator(ir
->opts
.ref_t
[0], friction
, ir
->delta_t
);
925 static_cast<BrownianIntegrator
*>(integ
)->setRandomNumberSeed(ir
->ld_seed
);
927 else if (EI_SD(ir
->eI
))
929 integ
= new LangevinIntegrator(ir
->opts
.ref_t
[0], friction
, ir
->delta_t
);
930 static_cast<LangevinIntegrator
*>(integ
)->setRandomNumberSeed(ir
->ld_seed
);
934 integ
= new VerletIntegrator(ir
->delta_t
);
935 if ( ir
->etc
!= etcNO
)
937 real collisionFreq
= ir
->opts
.tau_t
[0] / 1000; /* tau_t (ps) / 1000 = collisionFreq (fs^-1) */
938 AndersenThermostat
* thermostat
= new AndersenThermostat(ir
->opts
.ref_t
[0], friction
);
939 sys
->addForce(thermostat
);
942 integ
->setConstraintTolerance(ir
->shake_tol
);
944 // Create a context and initialize it.
945 Context
* context
= NULL
;
948 OpenMM could automatically select the "best" GPU, however we're not't
949 going to let it do that for now, as the current algorithm is very rudimentary
950 and we anyway support only CUDA.
951 if (platformOptStr == NULL || platformOptStr == "")
953 context = new Context(*sys, *integ);
958 // Find which platform is it.
959 for (int i
= 0; i
< Platform::getNumPlatforms() && context
== NULL
; i
++)
961 if (isStringEqNCase(opt
->getOptionValue("platform"), Platform::getPlatform(i
).getName()))
963 Platform
& platform
= Platform::getPlatform(i
);
964 // set standard properties
965 platform
.setPropertyDefaultValue("CudaDevice", opt
->getOptionValue("deviceid"));
966 // TODO add extra properties
967 context
= new Context(*sys
, *integ
, platform
);
972 gmx_fatal(FARGS
, "The requested platform \"%s\" could not be found.",
973 opt
->getOptionValue("platform").c_str());
977 Platform
& platform
= context
->getPlatform();
978 fprintf(fplog
, "Gromacs will use the OpenMM platform: %s\n", platform
.getName().c_str());
980 const vector
<string
>& properties
= platform
.getPropertyNames();
983 for (int i
= 0; i
< properties
.size(); i
++)
985 printf(">> %s: %s\n", properties
[i
].c_str(),
986 platform
.getPropertyValue(*context
, properties
[i
]).c_str());
987 fprintf(fplog
, ">> %s: %s\n", properties
[i
].c_str(),
988 platform
.getPropertyValue(*context
, properties
[i
]).c_str());
993 if (isStringEqNCase(opt
->getOptionValue("platform"), "CUDA"))
995 /* For now this is just to double-check if OpenMM selected the GPU we wanted,
996 but when we'll let OpenMM select the GPU automatically, it will query the devideId.
999 if (!from_string
<int>(tmp
, platform
.getPropertyValue(*context
, "CudaDevice"), std::dec
))
1001 gmx_fatal(FARGS
, "Internal error: couldn't determine the device selected by OpenMM");
1004 gmx_fatal(FARGS
, "Internal error: OpenMM is using device #%d"
1005 "while initialized for device #%d", tmp
, devId
);
1009 /* check GPU compatibility */
1010 char gpuname
[STRLEN
];
1011 devId
= atoi(opt
->getOptionValue("deviceid").c_str());
1012 if (!is_supported_cuda_gpu(-1, gpuname
))
1014 if (!gmx_strcasecmp(opt
->getOptionValue("force-device").c_str(), "yes"))
1016 sprintf(warn_buf
, "Non-supported GPU selected (#%d, %s), forced continuing."
1017 "Note, that the simulation can be slow or it migth even crash.",
1019 fprintf(fplog
, "%s\n", warn_buf
);
1020 gmx_warning(warn_buf
);
1024 gmx_fatal(FARGS
, "The selected GPU (#%d, %s) is not supported by Gromacs! "
1025 "Most probably you have a low-end GPU which would not perform well, "
1026 "or new hardware that has not been tested yet with Gromacs-OpenMM. "
1027 "If you still want to try using the device, use the force=on option.",
1033 fprintf(fplog
, "Gromacs will run on the GPU #%d (%s).\n", devId
, gpuname
);
1038 if (isStringEqNCase(opt
->getOptionValue("platform"), "CUDA"))
1040 /* pre-simulation memtest */
1041 runMemtest(fplog
, -1, "Pre", opt
);
1044 vector
<Vec3
> pos(numAtoms
);
1045 vector
<Vec3
> vel(numAtoms
);
1046 for (int i
= 0; i
< numAtoms
; ++i
)
1048 pos
[i
] = Vec3(state
->x
[i
][0], state
->x
[i
][1], state
->x
[i
][2]);
1049 vel
[i
] = Vec3(state
->v
[i
][0], state
->v
[i
][1], state
->v
[i
][2]);
1051 context
->setPositions(pos
);
1052 context
->setVelocities(vel
);
1054 // Return a structure containing the system, integrator, and context.
1055 OpenMMData
* data
= new OpenMMData();
1057 data
->integrator
= integ
;
1058 data
->context
= context
;
1059 data
->removeCM
= (ir
->nstcomm
> 0);
1060 data
->platformOpt
= opt
;
1064 catch (std::exception
& e
)
1066 gmx_fatal(FARGS
, "OpenMM exception caught while initializating: %s", e
.what());
1071 * \brief Integrate one step.
1073 * \param[in] data OpenMMData object created by openmm_init().
1075 void openmm_take_one_step(void* data
)
1077 // static int step = 0; printf("----> taking step #%d\n", step++);
1080 static_cast<OpenMMData
*>(data
)->integrator
->step(1);
1082 catch (std::exception
& e
)
1084 gmx_fatal(FARGS
, "OpenMM exception caught while taking a step: %s", e
.what());
1089 * \brief Integrate n steps.
1091 * \param[in] data OpenMMData object created by openmm_init().
1093 void openmm_take_steps(void* data
, int nstep
)
1097 static_cast<OpenMMData
*>(data
)->integrator
->step(nstep
);
1099 catch (std::exception
& e
)
1101 gmx_fatal(FARGS
, "OpenMM exception caught while taking a step: %s", e
.what());
1106 * \brief Clean up the data structures cretead for OpenMM.
1108 * \param[in] log Log file pointer.
1109 * \param[in] data OpenMMData object created by openmm_init().
1111 void openmm_cleanup(FILE* fplog
, void* data
)
1113 OpenMMData
* d
= static_cast<OpenMMData
*>(data
);
1115 if (isStringEqNCase(d
->platformOpt
->getOptionValue("platform"), "CUDA"))
1117 /* post-simulation memtest */
1118 runMemtest(fplog
, -1, "Post", d
->platformOpt
);
1121 delete d
->integrator
;
1123 delete d
->platformOpt
;
1128 * \brief Copy the current state information from OpenMM into the Gromacs data structures.
1130 * This function results in the requested proprties to be copied from the
1131 * GPU to host. As this represents a bottleneck, the frequency of pulling data
1132 * should be minimized.
1134 * \param[in] data OpenMMData object created by openmm_init().
1135 * \param[out] time Simulation time for which the state was created.
1136 * \param[out] state State of the system: coordinates and velocities.
1137 * \param[out] f Forces.
1138 * \param[out] enerd Energies.
1139 * \param[in] includePos True if coordinates are requested.
1140 * \param[in] includeVel True if velocities are requested.
1141 * \param[in] includeForce True if forces are requested.
1142 * \param[in] includeEnergy True if energies are requested.
1144 void openmm_copy_state(void *data
,
1145 t_state
*state
, double *time
,
1146 rvec f
[], gmx_enerdata_t
*enerd
,
1147 bool includePos
, bool includeVel
, bool includeForce
, bool includeEnergy
)
1151 types
+= State::Positions
;
1153 types
+= State::Velocities
;
1155 types
+= State::Forces
;
1157 types
+= State::Energy
;
1162 State currentState
= static_cast<OpenMMData
*>(data
)->context
->getState(types
);
1163 int numAtoms
= static_cast<OpenMMData
*>(data
)->system
->getNumParticles();
1166 for (int i
= 0; i
< numAtoms
; i
++)
1168 Vec3 x
= currentState
.getPositions()[i
];
1169 state
->x
[i
][0] = x
[0];
1170 state
->x
[i
][1] = x
[1];
1171 state
->x
[i
][2] = x
[2];
1176 for (int i
= 0; i
< numAtoms
; i
++)
1178 Vec3 v
= currentState
.getVelocities()[i
];
1179 state
->v
[i
][0] = v
[0];
1180 state
->v
[i
][1] = v
[1];
1181 state
->v
[i
][2] = v
[2];
1186 for (int i
= 0; i
< numAtoms
; i
++)
1188 Vec3 force
= currentState
.getForces()[i
];
1196 int numConstraints
= static_cast<OpenMMData
*>(data
)->system
->getNumConstraints();
1197 int dof
= 3*numAtoms
-numConstraints
;
1198 if (static_cast<OpenMMData
*>(data
)->removeCM
)
1200 enerd
->term
[F_EPOT
] = currentState
.getPotentialEnergy();
1201 enerd
->term
[F_EKIN
] = currentState
.getKineticEnergy();
1202 enerd
->term
[F_ETOT
] = enerd
->term
[F_EPOT
] + enerd
->term
[F_EKIN
];
1203 enerd
->term
[F_TEMP
] = 2.0*enerd
->term
[F_EKIN
]/dof
/BOLTZ
;
1205 *time
= currentState
.getTime();
1207 catch (std::exception
& e
)
1209 gmx_fatal(FARGS
, "OpenMM exception caught while retrieving state information: %s", e
.what());