15 #include "gmx_fatal.h"
20 #include "gmx_gpu_utils.h"
21 #include "mtop_util.h"
23 #include "openmm_wrapper.h"
25 using namespace OpenMM
;
27 #define MEM_ERR_MSG(str) \
28 "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
29 "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
30 "overclocked and that the device is properly cooled.\n", (str)
32 /** Convert string to type T. */
34 static bool from_string(T
& t
, const string
& s
, ios_base
& (*f
)(ios_base
&))
37 return !(iss
>> f
>> t
).fail();
41 * Split string around a given delimiter.
43 static vector
<string
> split(const string
&s
, char delim
)
48 while(getline(ss
, item
, delim
))
50 if (item
.length() != 0)
51 elems
.push_back(item
);
57 * Split a string "option=value" into "option" and "value" strings.
59 static void split_opt_val(const string
&s
, string
&opt
, string
&val
)
61 size_t eqPos
= s
.find('=');
62 if (eqPos
!= string::npos
)
64 opt
= s
.substr(0, eqPos
);
65 if (eqPos
!= s
.length()) val
= s
.substr(eqPos
+1);
70 * Compare two strings ignoring case.
72 static bool isStringEqNCase(const string s1
, const string s2
)
74 return (gmx_strncasecmp(s1
.c_str(), s2
.c_str(), max(s1
.length(), s2
.length())) == 0);
78 * Conver string to upper case.
80 static string
toUpper(const string
&s
)
83 std::transform(stmp
.begin(), stmp
.end(), stmp
.begin(), static_cast < int(*)(int) > (toupper
));
87 #define SIZEOF_PLATFORMS 1
88 #define SIZEOF_MEMTESTS 3
89 #define SIZEOF_DEVICEIDS 1
90 #define SIZEOF_FORCE_DEV 2
92 /** Possible options of the mdrun -device parameter. */
93 static const char *devOptStrings
[] = { "platform", "deviceid", "memtest", "force-device" };
102 * Parse the options string provided to mdrun.
104 class GmxOpenMMPlatformOptions
107 GmxOpenMMPlatformOptions(const char *optionString
);
108 // GmxOpenMMPlatformOptions(string &optionString);
109 ~GmxOpenMMPlatformOptions() { options
.clear(); }
110 string
getOptionValue(const string
&optName
);
111 void remOption(const string
&optName
) { options
.erase(toUpper(optName
)); }
113 void setOption(const string
&opt
, const string
&val
);
114 map
<string
, string
> options
;
115 static const char * const platforms
[SIZEOF_PLATFORMS
];
116 static const char * const memtests
[SIZEOF_MEMTESTS
];
117 static const char * const deviceid
[SIZEOF_DEVICEIDS
];
118 static const char * const force_dev
[SIZEOF_FORCE_DEV
];
121 /* possible values of the parameters that will not be passed to OMM
122 first value will always be the default used in case if the option is not specified */
123 const char * const GmxOpenMMPlatformOptions::platforms
[SIZEOF_PLATFORMS
] = { "Cuda" /*,"OpenCL"*/ };
124 const char * const GmxOpenMMPlatformOptions::memtests
[SIZEOF_MEMTESTS
] = { "15", "full", "off" }; /* also valid any positive integer >15 */
125 const char * const GmxOpenMMPlatformOptions::deviceid
[SIZEOF_DEVICEIDS
] = { "0" }; /* also valid any positive integer */
126 const char * const GmxOpenMMPlatformOptions::force_dev
[SIZEOF_FORCE_DEV
] = { "no", "yes" };
128 GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString
)
130 // set default values
131 setOption("platform", platforms
[0]);
132 setOption("memtest", memtests
[0]);
133 setOption("deviceid", deviceid
[0]);
134 setOption("force-device", force_dev
[0]);
136 string
opt(optionString
);
138 // remove all the whitespaces
139 opt
.erase(remove_if(opt
.begin(), opt
.end(), ::isspace
), opt
.end());
140 // tokenize around ","-s
141 vector
<string
> tokens
= split(opt
, ',');
143 for (vector
<string
>::iterator it
= tokens
.begin(); it
!= tokens
.end(); ++it
)
145 string opt
= "", val
= "";
146 split_opt_val(*it
, opt
, val
);
148 if (isStringEqNCase(opt
, "platform"))
154 if (isStringEqNCase(opt
, "memtest"))
156 if (!isStringEqNCase(val
, "full") && !isStringEqNCase(val
, "off")) /* the value has to be an integer >15 */
159 if (!from_string
<int>(secs
, val
, std::dec
))
161 gmx_fatal(FARGS
, "Invalid value for option memtestoption: \"%s\"!\n", val
.c_str());
165 gmx_fatal(FARGS
, "Incorrect value for memtest option (%d). Memtest needs to run for at least 15s!\n", secs
);
172 if (isStringEqNCase(opt
, "deviceid"))
175 if (!from_string
<int>(id
, val
, std::dec
) )
177 gmx_fatal(FARGS
, "Invalid device id: \"%s\"!\n", val
.c_str());
183 if (isStringEqNCase(opt
,"force-device"))
185 if (!isStringEqNCase(val
, "yes") && !isStringEqNCase(val
, "no"))
187 gmx_fatal(FARGS
, "Invalid OpenMM force option: \"%s\"!\n", val
.c_str());
193 // if we got till here something went wrong
194 gmx_fatal(FARGS
, "Invalid OpenMM platform option: \"%s\"!\n", (*it
).c_str());
197 /* cout << "== platform = " << getOptionValue("platform") << endl
198 << "== deviceID = " << getOptionValue("deviceid") << endl
199 << "== memtest = " << getOptionValue("memtest") << endl
200 << "== force = " << getOptionValue("force-device") << endl;
204 string
GmxOpenMMPlatformOptions::getOptionValue(const string
&optName
)
206 if (options
.find(toUpper(optName
)) != options
.end())
208 return options
[toUpper(optName
)];
216 void GmxOpenMMPlatformOptions::setOption(const string
&opt
, const string
&val
)
218 options
[toUpper(opt
)] = val
;
226 Integrator
* integrator
;
228 GmxOpenMMPlatformOptions
*platformOpt
;
231 void run_memtest(FILE* fplog
, int devId
, const char* pre_post
, GmxOpenMMPlatformOptions
*opt
)
233 // TODO I guess the log entries should go on stdout as well, shouldn't they? [sz]
236 const char * test_type
= opt
->getOptionValue("memtest").c_str();
237 if (!gmx_strcasecmp(test_type
, "off"))
243 if (!gmx_strcasecmp(test_type
, "full"))
249 from_string
<int>(which_test
, test_type
, std::dec
);
255 case 0: /* no memtest */
257 sprintf(warn_buf
, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
258 "incorrect results!\n", pre_post
);
259 fprintf(fplog
, "%s", warn_buf
);
263 case 1: /* quick memtest */
264 fprintf(fplog
, "%s-simulation %s GPU memtest in progress...\n", pre_post
, test_type
);
265 fprintf(stdout
, "\n%s-simulation %s GPU memtest in progress...", pre_post
, test_type
);
266 fflush(fplog
); fflush(stdout
);
267 if (do_quick_memtest(-1) != 0)
269 gmx_fatal(FARGS
,MEM_ERR_MSG(pre_post
));
274 fprintf(fplog
, "Memory test completed without errors.\n");
275 fprintf(stdout
, "done, no errors detected\n");
279 case 2: /* full memtest */
280 fprintf(fplog
, "%s-simulation %s memtest in progress...\n", pre_post
, test_type
);
281 fprintf(stdout
, "\n%s-simulation %s memtest in progress...", pre_post
, test_type
);
282 fflush(fplog
); fflush(stdout
);
283 if (do_full_memtest(-1) != 0)
285 gmx_fatal(FARGS
, MEM_ERR_MSG(pre_post
) );
290 fprintf(fplog
, "Memory test completed without errors.\n");
291 fprintf(stdout
, "done, no errors detected\n");
295 default: /* timed memtest */
296 fprintf(fplog
, "%s-simulation memtest for ~%ds in progress...\n", pre_post
, which_test
);
297 fprintf(stdout
, "\n%s-simulation memtest for ~%ds in progress...", pre_post
, which_test
);
298 fflush(fplog
); fflush(stdout
);
299 if (do_timed_memtest(-1, which_test
) != 0)
301 gmx_fatal(FARGS
, MEM_ERR_MSG(pre_post
));
306 fprintf(fplog
, "Memory test completed without errors.\n");
307 fprintf(stdout
, "done, no errors detected.\n");
310 fflush(fplog
); fflush(stdout
);
313 void checkGmxOptions(t_inputrec
*ir
, gmx_localtop_t
*top
)
315 // Abort if unsupported critical options are present
318 if ( (ir
->eI
!= eiVV
) &&
319 (ir
->eI
!= eiVVAK
) &&
325 gmx_fatal(FARGS
, "** OpenMM Error ** : Unsupported integrator requested."
326 "Available integrators are: md-vv/md-vvak, sd/sd1, and bd. \n");
330 if ((ir
->coulombtype
!= eelPME
) && (ir
->coulombtype
!= eelRF
) && (ir
->coulombtype
!= eelEWALD
))
332 gmx_fatal(FARGS
,"** OpenMM Error ** : Unsupported method for electrostatics. "
333 "Use NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.\n");
336 /* TODO what is this code checking? */
337 if (ir
->bPeriodicMols
)
338 gmx_fatal(FARGS
,"** OpenMM Error ** : Systems with periodic molecules ares not supported\n");
340 if ( (ir
->etc
!= etcNO
) && (ir
->etc
!= etcANDERSEN
) && (ir
->etc
!= etcANDERSENINTERVAL
))
341 gmx_fatal(FARGS
,"** OpenMM Error ** : Temperature coupling can be achieved by "
342 "using either \n\t(1)\t\"md-vv\" or \"md-vvak\" integrators with \"andersen\" or "
343 "\"andersen-interval\" thermostat, or \n\t(2)\t\"sd\",\"sd1\" or \"bd\" integrators\n");
345 if (ir
->opts
.ngtc
> 1)
346 gmx_fatal(FARGS
,"** OpenMM Error ** : Multiple temperature coupling groups are not supported. \n");
348 if (ir
->epc
!= etcNO
)
349 gmx_fatal(FARGS
,"** OpenMM Error ** : Pressure coupling is not supported. \n");
351 if (ir
->opts
.annealing
[0])
352 gmx_fatal(FARGS
,"** OpenMM Error ** : Simulated annealing is not supported. \n");
354 if (ir
->eConstrAlg
!= econtSHAKE
)
355 warning_note("** OpenMM Warning ** : Constraints in OpenMM are done by a combination "
356 "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
357 "by the \"shake_tol\" option.");
360 gmx_fatal(FARGS
,"** OpenMM Error ** : Walls are not supported.\n");
362 if (ir
->ePull
!= epullNO
)
363 gmx_fatal(FARGS
,"** OpenMM Error ** : Pulling is not supported.\n");
365 if (top
->idef
.il
[F_DISRES
].nr
> 0)
366 gmx_fatal(FARGS
,"** OpenMM Error ** : Distant restraints are not supported.\n");
368 if (top
->idef
.il
[F_ORIRES
].nr
> 0)
369 gmx_fatal(FARGS
,"** OpenMM Error ** : Orientation restraints are not supported.\n");
371 if (top
->idef
.il
[F_ANGRES
].nr
> 0)
372 gmx_fatal(FARGS
,"** OpenMM Error ** : Angle restraints are not supported.\n");
374 if (top
->idef
.il
[F_DIHRES
].nr
> 0)
375 gmx_fatal(FARGS
,"** OpenMM Error ** : Dihedral restraints are not supported.\n");
377 if (ir
->efep
!= efepNO
)
378 gmx_fatal(FARGS
,"** OpenMM Error ** : Free energy calculations are not supported.\n");
380 if (ir
->opts
.ngacc
> 1)
381 gmx_fatal(FARGS
,"** OpenMM Error ** : Non-equilibrium MD (accelerated groups) are "
382 "not supported. \n");
384 if (IR_ELEC_FIELD(*ir
))
385 gmx_fatal(FARGS
,"** OpenMM Error ** : Electric fields are not supported. \n");
388 gmx_fatal(FARGS
,"** OpenMM Error ** : QMMM calculations are not supported. \n");
390 if (ir
->rcoulomb
!= ir
->rvdw
)
391 gmx_fatal(FARGS
,"** OpenMM Error ** : OpenMM uses a single cutoff for both Coulomb "
392 "and VdW interactions. Please set rcoulomb equal to rvdw. \n");
397 * Initialize OpenMM, and return a pointer to the OpenMMData object containing the System, Integrator, and Context.
399 void* openmm_init(FILE *fplog
, const char *platformOptStr
,
400 t_commrec
*cr
,t_inputrec
*ir
,
401 gmx_mtop_t
*top_global
, gmx_localtop_t
*top
,
402 t_mdatoms
*mdatoms
, t_forcerec
*fr
,t_state
*state
)
404 static bool hasLoadedPlugins
= false;
405 string usedPluginDir
;
408 if (!hasLoadedPlugins
)
410 vector
<string
> loadedPlugins
;
411 /* Look for OpenMM plugins at various locations (listed in order of priority):
412 - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
413 - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
414 - at the default location assumed by OpenMM
417 char *pluginDir
= getenv("OPENMM_PLUGIN_DIR");
419 /* no env var or empty */
420 if (pluginDir
!= NULL
&& *pluginDir
!= '\0')
422 loadedPlugins
= Platform::loadPluginsFromDirectory(pluginDir
);
423 if (loadedPlugins
.size() > 0)
425 hasLoadedPlugins
= true;
426 usedPluginDir
= pluginDir
;
430 gmx_fatal(FARGS
, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
431 "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!", pluginDir
);
435 /* macro set at build time */
436 #ifdef OPENMM_PLUGIN_DIR
437 if (!hasLoadedPlugins
)
439 loadedPlugins
= Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR
);
440 if (loadedPlugins
.size() > 0)
442 hasLoadedPlugins
= true;
443 usedPluginDir
= OPENMM_PLUGIN_DIR
;
447 /* default loocation */
448 if (!hasLoadedPlugins
)
450 loadedPlugins
= Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
451 if (loadedPlugins
.size() > 0)
453 hasLoadedPlugins
= true;
454 usedPluginDir
= Platform::getDefaultPluginsDirectory();
458 /* if there are still no plugins loaded there won't be any */
459 if (!hasLoadedPlugins
)
461 gmx_fatal(FARGS
, "No OpenMM plugins were found! You can provide the"
462 " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir
);
465 fprintf(fplog
, "\nPlugins loaded from directory %s:\t", usedPluginDir
.c_str());
466 for (int i
= 0; i
< loadedPlugins
.size(); i
++)
468 fprintf(fplog
, "%s, ", loadedPlugins
[i
].c_str());
470 fprintf(fplog
, "\n");
473 /* parse option string */
474 GmxOpenMMPlatformOptions
*opt
= new GmxOpenMMPlatformOptions(platformOptStr
);
476 /* check wheter Gromacs options compatibility with OpenMM */
477 checkGmxOptions(ir
, top
);
479 /* check GPU support */
481 is_supported_cuda_gpu(atoi(opt
->getOptionValue("deviceid").c_str()), s
);
483 // Create the system.
484 const t_idef
& idef
= top
->idef
;
485 const int numAtoms
= top_global
->natoms
;
486 const int numConstraints
= idef
.il
[F_CONSTR
].nr
/3;
487 const int numSettle
= idef
.il
[F_SETTLE
].nr
/2;
488 const int numBonds
= idef
.il
[F_BONDS
].nr
/3;
489 const int numAngles
= idef
.il
[F_ANGLES
].nr
/4;
490 const int numPeriodic
= idef
.il
[F_PDIHS
].nr
/5;
491 const int numRB
= idef
.il
[F_RBDIHS
].nr
/5;
492 const int num14
= idef
.il
[F_LJ14
].nr
/3;
493 System
* sys
= new System();
495 sys
->addForce(new CMMotionRemover(ir
->nstcomm
));
497 // Set bonded force field terms.
498 const int* bondAtoms
= (int*) idef
.il
[F_BONDS
].iatoms
;
499 HarmonicBondForce
* bondForce
= new HarmonicBondForce();
500 sys
->addForce(bondForce
);
502 for (int i
= 0; i
< numBonds
; ++i
) {
503 int type
= bondAtoms
[offset
++];
504 int atom1
= bondAtoms
[offset
++];
505 int atom2
= bondAtoms
[offset
++];
506 bondForce
->addBond(atom1
, atom2
, idef
.iparams
[type
].harmonic
.rA
, idef
.iparams
[type
].harmonic
.krA
);
508 const int* angleAtoms
= (int*) idef
.il
[F_ANGLES
].iatoms
;
509 HarmonicAngleForce
* angleForce
= new HarmonicAngleForce();
510 sys
->addForce(angleForce
);
512 for (int i
= 0; i
< numAngles
; ++i
) {
513 int type
= angleAtoms
[offset
++];
514 int atom1
= angleAtoms
[offset
++];
515 int atom2
= angleAtoms
[offset
++];
516 int atom3
= angleAtoms
[offset
++];
517 angleForce
->addAngle(atom1
, atom2
, atom3
, idef
.iparams
[type
].harmonic
.rA
*M_PI
/180.0, idef
.iparams
[type
].harmonic
.krA
);
519 const int* periodicAtoms
= (int*) idef
.il
[F_PDIHS
].iatoms
;
520 PeriodicTorsionForce
* periodicForce
= new PeriodicTorsionForce();
521 sys
->addForce(periodicForce
);
523 for (int i
= 0; i
< numPeriodic
; ++i
) {
524 int type
= periodicAtoms
[offset
++];
525 int atom1
= periodicAtoms
[offset
++];
526 int atom2
= periodicAtoms
[offset
++];
527 int atom3
= periodicAtoms
[offset
++];
528 int atom4
= periodicAtoms
[offset
++];
529 periodicForce
->addTorsion(atom1
, atom2
, atom3
, atom4
, idef
.iparams
[type
].pdihs
.mult
, idef
.iparams
[type
].pdihs
.phiA
*M_PI
/180.0, idef
.iparams
[type
].pdihs
.cpA
);
531 const int* rbAtoms
= (int*) idef
.il
[F_RBDIHS
].iatoms
;
532 RBTorsionForce
* rbForce
= new RBTorsionForce();
533 sys
->addForce(rbForce
);
535 for (int i
= 0; i
< numRB
; ++i
) {
536 int type
= rbAtoms
[offset
++];
537 int atom1
= rbAtoms
[offset
++];
538 int atom2
= rbAtoms
[offset
++];
539 int atom3
= rbAtoms
[offset
++];
540 int atom4
= rbAtoms
[offset
++];
541 rbForce
->addTorsion(atom1
, atom2
, atom3
, atom4
, idef
.iparams
[type
].rbdihs
.rbcA
[0], idef
.iparams
[type
].rbdihs
.rbcA
[1],
542 idef
.iparams
[type
].rbdihs
.rbcA
[2], idef
.iparams
[type
].rbdihs
.rbcA
[3], idef
.iparams
[type
].rbdihs
.rbcA
[4], idef
.iparams
[type
].rbdihs
.rbcA
[5]);
545 // Set nonbonded parameters and masses.
547 int ntypes
= fr
->ntype
;
548 int* types
= mdatoms
->typeA
;
549 real
* nbfp
= fr
->nbfp
;
550 real
* charges
= mdatoms
->chargeA
;
551 real
* masses
= mdatoms
->massT
;
552 NonbondedForce
* nonbondedForce
= new NonbondedForce();
553 sys
->addForce(nonbondedForce
);
555 if (ir
->rcoulomb
== 0)
556 nonbondedForce
->setNonbondedMethod(NonbondedForce::NoCutoff
);
559 switch (ir
->coulombtype
)
561 case eelRF
: // TODO what is the correct condition?
562 if (ir
->ePBC
== epbcXYZ
) {
563 nonbondedForce
->setNonbondedMethod(NonbondedForce::CutoffPeriodic
);
564 sys
->setPeriodicBoxVectors(Vec3(state
->box
[0][0], 0, 0), Vec3(0, state
->box
[1][1], 0), Vec3(0, 0, state
->box
[2][2]));
566 else if (ir
->ePBC
== epbcNONE
)
567 nonbondedForce
->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic
);
569 gmx_fatal(FARGS
,"** OpenMM Error ** : Only full periodic boundary conditions (pbc = xyz), or none (pbc = no) are supported\n");
570 nonbondedForce
->setCutoffDistance(ir
->rcoulomb
);
574 if (ir
->ewald_geometry
== eewg3DC
)
575 gmx_fatal(FARGS
,"** OpenMM Error ** : Only Ewald 3D geometry is supported\n");
576 if (ir
->epsilon_surface
!= 0)
577 gmx_fatal(FARGS
,"** OpenMM Error ** : Dipole correction in Ewald summation is not supported\n");
578 nonbondedForce
->setNonbondedMethod(NonbondedForce::Ewald
);
579 nonbondedForce
->setCutoffDistance(ir
->rcoulomb
);
580 sys
->setPeriodicBoxVectors(Vec3(state
->box
[0][0], 0, 0), Vec3(0, state
->box
[1][1], 0), Vec3(0, 0, state
->box
[2][2]));
584 nonbondedForce
->setNonbondedMethod(NonbondedForce::PME
);
585 nonbondedForce
->setCutoffDistance(ir
->rcoulomb
);
586 sys
->setPeriodicBoxVectors(Vec3(state
->box
[0][0], 0, 0), Vec3(0, state
->box
[1][1], 0), Vec3(0, 0, state
->box
[2][2]));
590 gmx_fatal(FARGS
,"Internal error: you should not see this message, it that the"
591 "electrosatics option check failed. Please report this error!");
595 for (int i
= 0; i
< numAtoms
; ++i
) {
596 real c6
= nbfp
[types
[i
]*2*ntypes
+types
[i
]*2];
597 real c12
= nbfp
[types
[i
]*2*ntypes
+types
[i
]*2+1];
599 nonbondedForce
->addParticle(charges
[i
], 1.0, 0.0);
601 nonbondedForce
->addParticle(charges
[i
], pow(c12
/c6
, (real
) (1.0/6.0)), c6
*c6
/(4.0*c12
));
602 sys
->addParticle(masses
[i
]);
605 // Build a table of all exclusions.
607 vector
<set
<int> > exclusions(numAtoms
);
608 for (int i
= 0; i
< numAtoms
; i
++) {
609 int start
= top
->excls
.index
[i
];
610 int end
= top
->excls
.index
[i
+1];
611 for (int j
= start
; j
< end
; j
++)
612 exclusions
[i
].insert(top
->excls
.a
[j
]);
615 // Record the 1-4 interactions, and remove them from the list of exclusions.
617 const int* nb14Atoms
= (int*) idef
.il
[F_LJ14
].iatoms
;
619 for (int i
= 0; i
< num14
; ++i
) {
620 int type
= nb14Atoms
[offset
++];
621 int atom1
= nb14Atoms
[offset
++];
622 int atom2
= nb14Atoms
[offset
++];
623 real c6
= idef
.iparams
[type
].lj14
.c6A
;
624 real c12
= idef
.iparams
[type
].lj14
.c12A
;
627 epsilon
= (real
) 0.0;
631 epsilon
= (real
) ((c6
*c6
)/(4.0*c12
));
632 sigma
= (real
) pow(c12
/c6
, (real
) (1.0/6.0));
634 nonbondedForce
->addException(atom1
, atom2
, fr
->fudgeQQ
*charges
[atom1
]*charges
[atom2
], sigma
, epsilon
);
635 exclusions
[atom1
].erase(atom2
);
636 exclusions
[atom2
].erase(atom1
);
639 // Record exclusions.
641 for (int i
= 0; i
< numAtoms
; i
++) {
642 for (set
<int>::const_iterator iter
= exclusions
[i
].begin(); iter
!= exclusions
[i
].end(); ++iter
) {
644 nonbondedForce
->addException(i
, *iter
, 0.0, 1.0, 0.0);
648 // Add GBSA if needed.
650 atoms
= gmx_mtop_global_atoms(top_global
);
652 if (ir
->implicit_solvent
== eisGBSA
) {
653 GBSAOBCForce
* gbsa
= new GBSAOBCForce();
655 gbsa
->setSoluteDielectric(ir
->epsilon_r
);
656 gbsa
->setSolventDielectric(ir
->gb_epsilon_solvent
);
657 gbsa
->setCutoffDistance(nonbondedForce
->getCutoffDistance());
658 if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::NoCutoff
)
659 gbsa
->setNonbondedMethod(GBSAOBCForce::NoCutoff
);
660 else if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic
)
661 gbsa
->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic
);
662 else if (nonbondedForce
->getNonbondedMethod() == NonbondedForce::CutoffPeriodic
)
663 gbsa
->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic
);
665 gmx_fatal(FARGS
,"** OpenMM Error ** : Only Reaction-Field electrostatics is supported with OBC/GBSA.\n");
667 for (int i
= 0; i
< numAtoms
; ++i
)
668 gbsa
->addParticle(charges
[i
],
669 top_global
->atomtypes
.gb_radius
[atoms
.atom
[i
].type
],
670 top_global
->atomtypes
.S_hct
[atoms
.atom
[i
].type
]);
675 const int* constraintAtoms
= (int*) idef
.il
[F_CONSTR
].iatoms
;
677 for (int i
= 0; i
< numConstraints
; ++i
) {
678 int type
= constraintAtoms
[offset
++];
679 int atom1
= constraintAtoms
[offset
++];
680 int atom2
= constraintAtoms
[offset
++];
681 sys
->addConstraint(atom1
, atom2
, idef
.iparams
[type
].constr
.dA
);
683 const int* settleAtoms
= (int*) idef
.il
[F_SETTLE
].iatoms
;
685 for (int i
= 0; i
< numSettle
; ++i
) {
686 int type
= settleAtoms
[offset
++];
687 int oxygen
= settleAtoms
[offset
++];
688 sys
->addConstraint(oxygen
, oxygen
+1, idef
.iparams
[type
].settle
.doh
);
689 sys
->addConstraint(oxygen
, oxygen
+2, idef
.iparams
[type
].settle
.doh
);
690 sys
->addConstraint(oxygen
+1, oxygen
+2, idef
.iparams
[type
].settle
.dhh
);
693 // Create an integrator for simulating the system.
695 real friction
= (ir
->opts
.tau_t
[0] == 0.0 ? 0.0 : 1.0/ir
->opts
.tau_t
[0]);
697 if (ir
->eI
== eiVV
|| ir
->eI
== eiVVAK
) {
698 integ
= new VerletIntegrator(ir
->delta_t
);
699 if ( ir
->etc
== etcANDERSEN
) {
700 real collisionFreq
= ir
->opts
.tau_t
[0] / 1000; /* tau_t (ps) / 1000 = collisionFreq (fs^-1) */
701 AndersenThermostat
* thermostat
= new AndersenThermostat(ir
->opts
.ref_t
[0], friction
); /* TODO test this */
702 sys
->addForce(thermostat
);
706 else if (ir
->eI
== eiBD
) {
707 integ
= new BrownianIntegrator(ir
->opts
.ref_t
[0], friction
, ir
->delta_t
);
708 static_cast<BrownianIntegrator
*>(integ
)->setRandomNumberSeed(ir
->ld_seed
); /* TODO test this */
710 else if (EI_SD(ir
->eI
)) {
711 integ
= new LangevinIntegrator(ir
->opts
.ref_t
[0], friction
, ir
->delta_t
);
712 static_cast<LangevinIntegrator
*>(integ
)->setRandomNumberSeed(ir
->ld_seed
); /* TODO test this */
715 gmx_fatal(FARGS
, "** OpenMM Error ** : Unsupported integrator requested."
716 "Available integrators are: md-vv/md-vvak, sd/sd1, and bd. \n");
719 integ
->setConstraintTolerance(ir
->shake_tol
);
721 // Create a context and initialize it.
722 Context
* context
= NULL
;
723 if (platformOptStr
== NULL
|| platformOptStr
== "")
725 context
= new Context(*sys
, *integ
);
729 // Find which platform is it.
730 for (int i
= 0; i
< Platform::getNumPlatforms() && context
== NULL
; i
++)
732 if (isStringEqNCase(opt
->getOptionValue("platform"), Platform::getPlatform(i
).getName()))
734 Platform
& platform
= Platform::getPlatform(i
);
735 // set standard properties
736 platform
.setPropertyDefaultValue("CudaDevice", opt
->getOptionValue("deviceid"));
737 // TODO add extra properties
738 context
= new Context(*sys
, *integ
, platform
);
743 gmx_fatal(FARGS
, "The requested platform \"%s\" could not be found.\n", opt
->getOptionValue("platform").c_str());
747 Platform
& platform
= context
->getPlatform();
748 fprintf(fplog
, "Gromacs will use the OpenMM platform: %s\n", platform
.getName().c_str());
750 const vector
<string
>& properties
= platform
.getPropertyNames();
753 for (int i
= 0; i
< properties
.size(); i
++)
755 printf(">> %s: %s\n", properties
[i
].c_str(), platform
.getPropertyValue(*context
, properties
[i
]).c_str());
756 fprintf(fplog
, ">> %s: %s\n", properties
[i
].c_str(), platform
.getPropertyValue(*context
, properties
[i
]).c_str());
761 if (!from_string
<int>(devId
, platform
.getPropertyValue(*context
, "CudaDevice"), std::dec
))
763 gmx_fatal(FARGS
, "Internal error: couldn't determine the device selected by OpenMM");
766 /* check GPU compatibility */
767 char gpuname
[STRLEN
];
768 if (!is_supported_cuda_gpu(-1, gpuname
))
770 if (!gmx_strcasecmp(opt
->getOptionValue("force-device").c_str(), "yes"))
772 sprintf(warn_buf
, "Non-supported GPU selected (#%d, %s), forced continuing.\n"
773 "Note, that the simulation can be slow or it migth even crash.", devId
, gpuname
);
774 fprintf(fplog
, "%s", warn_buf
);
779 gmx_fatal(FARGS
, "The selected GPU (#%d, %s) is not supported by Gromacs! "
780 "Most probably you have a low-end GPU which would not perform well, or new hardware that"
781 "has not been tested yet with Gromacs-OpenMM. If you still want to try using this "
782 "device use the force=on option.", devId
, gpuname
);
787 fprintf(fplog
, "Gromacs will run on the GPU #%d (%s).\n", devId
, gpuname
);
790 /* do the pre-simulation memtest */
791 run_memtest(fplog
, -1, "Pre", opt
);
793 vector
<Vec3
> pos(numAtoms
);
794 vector
<Vec3
> vel(numAtoms
);
795 for (int i
= 0; i
< numAtoms
; ++i
) {
796 pos
[i
] = Vec3(state
->x
[i
][0], state
->x
[i
][1], state
->x
[i
][2]);
797 vel
[i
] = Vec3(state
->v
[i
][0], state
->v
[i
][1], state
->v
[i
][2]);
799 context
->setPositions(pos
);
800 context
->setVelocities(vel
);
802 // Return a structure containing the system, integrator, and context.
803 OpenMMData
* data
= new OpenMMData();
805 data
->integrator
= integ
;
806 data
->context
= context
;
807 data
->removeCM
= (ir
->nstcomm
> 0);
808 data
->platformOpt
= opt
;
811 } catch (std::exception
& e
) {
812 gmx_fatal(FARGS
, "OpenMM exception caught while initializating: %s\n", e
.what());
817 * Integrate one step.
819 * @param data the OpenMMData object created by openmm_init().
821 void openmm_take_one_step(void* data
)
823 // static int step = 0; printf("----> taking step #%d\n", step++);
825 static_cast<OpenMMData
*>(data
)->integrator
->step(1);
826 } catch (std::exception
& e
) {
827 gmx_fatal(FARGS
, "OpenMM exception caught while taking a step: %s\n", e
.what());
834 * @param data the OpenMMData object created by openmm_init().
836 void openmm_take_steps(void* data
, int nstep
)
839 static_cast<OpenMMData
*>(data
)->integrator
->step(nstep
);
840 } catch (std::exception
& e
) {
841 gmx_fatal(FARGS
, "OpenMM exception caught while taking a step: %s\n", e
.what());
846 * Clean up all the data structures used by OpenMM.
848 * @param log file pointer
849 * @param data the OpenMMData object created by openmm_init().
851 void openmm_cleanup(FILE* fplog
, void* data
)
853 OpenMMData
* d
= static_cast<OpenMMData
*>(data
);
854 run_memtest(fplog
, -1, "Post", d
->platformOpt
);
856 delete d
->integrator
;
858 delete d
->platformOpt
;
863 * Copy the current state information (positions, velocities, and forces) into the data structures used
866 * @param data the OpenMMData object created by openmm_init().
868 void openmm_copy_state(void *data
,
869 t_state
*state
, double *time
,
870 rvec f
[], gmx_enerdata_t
*enerd
,
871 bool includePos
, bool includeVel
, bool includeForce
, bool includeEnergy
)
875 types
+= State::Positions
;
877 types
+= State::Velocities
;
879 types
+= State::Forces
;
881 types
+= State::Energy
;
885 State currentState
= static_cast<OpenMMData
*>(data
)->context
->getState(types
);
886 int numAtoms
= static_cast<OpenMMData
*>(data
)->system
->getNumParticles();
888 for (int i
= 0; i
< numAtoms
; i
++) {
889 Vec3 x
= currentState
.getPositions()[i
];
890 state
->x
[i
][0] = x
[0];
891 state
->x
[i
][1] = x
[1];
892 state
->x
[i
][2] = x
[2];
896 for (int i
= 0; i
< numAtoms
; i
++) {
897 Vec3 v
= currentState
.getVelocities()[i
];
898 state
->v
[i
][0] = v
[0];
899 state
->v
[i
][1] = v
[1];
900 state
->v
[i
][2] = v
[2];
904 for (int i
= 0; i
< numAtoms
; i
++) {
905 Vec3 force
= currentState
.getForces()[i
];
912 int numConstraints
= static_cast<OpenMMData
*>(data
)->system
->getNumConstraints();
913 int dof
= 3*numAtoms
-numConstraints
;
914 if (static_cast<OpenMMData
*>(data
)->removeCM
)
916 enerd
->term
[F_EPOT
] = currentState
.getPotentialEnergy();
917 enerd
->term
[F_EKIN
] = currentState
.getKineticEnergy();
918 enerd
->term
[F_ETOT
] = enerd
->term
[F_EPOT
] + enerd
->term
[F_EKIN
];
919 enerd
->term
[F_TEMP
] = 2.0*enerd
->term
[F_EKIN
]/dof
/BOLTZ
;
921 *time
= currentState
.getTime();
922 } catch (std::exception
& e
) {
923 gmx_fatal(FARGS
, "OpenMM exception caught while retrieving state information: %s\n", e
.what());