3343aba94fa07f606d151be8bcbf5fbff0be54ac
[alexxy/gromacs.git] / src / contrib / openmm_wrapper.cpp
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  * 
4  *                This source code is part of
5  * 
6  *                 G   R   O   M   A   C   S
7  * 
8  *          GROningen MAchine for Chemical Simulations
9  * 
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2010, 2013, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser 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.
19  * 
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.
26  * 
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.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
34  */
35
36 /*
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
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #include <types/simple.h>
47 #include <cmath>
48 #include <set>
49 #include <iostream>
50 #include <sstream>
51 #include <fstream>
52 #include <map>
53 #include <vector>
54 #include <cctype>
55 #include <algorithm>
56
57 using namespace std;
58
59 #include "OpenMM.h"
60
61 #include "gmx_fatal.h"
62 #include "typedefs.h"
63 #include "mdrun.h"
64 #include "physics.h"
65 #include "string2.h"
66 #include "openmm_gpu_utils.h"
67 #include "gpu_utils.h"
68 #include "mtop_util.h"
69
70 #include "openmm_wrapper.h"
71
72 using namespace OpenMM;
73
74 /*! \cond */
75 #define MEM_ERR_MSG(str) \
76     "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
77     "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
78     "overclocked and that the device is properly cooled.\n", (str)
79 /*! \endcond */
80
81 #define COMBRULE_CHK_TOL            1e-6
82 #define COMBRULE_SIGMA(sig1, sig2)  (((sig1) + (sig2))/2)
83 #define COMBRULE_EPS(eps1, eps2)    (sqrt((eps1) * (eps2)))
84
85 /*! 
86  * \brief Convert string to integer type.
87  * \param[in]  s    String to convert from.
88  * \param[in]  f    Basefield format flag that takes any of the following I/O
89  *                  manipulators: dec, hex, oct.
90  * \param[out] t    Destination variable to convert to.
91  */
92 template <class T>
93 static gmx_bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
94 {
95     istringstream iss(s);
96     return !(iss >> f >> t).fail();
97 }
98
99 /*!
100  * \brief Split string around a given delimiter.
101  * \param[in] s      String to split.
102  * \param[in] delim  Delimiter character.
103  * \returns          Vector of strings found in \p s.
104  */
105 static vector<string> split(const string &s, char delim)
106 {
107     vector<string> elems;
108     stringstream ss(s);
109     string item;
110     while (getline(ss, item, delim))
111     {
112         if (item.length() != 0)
113             elems.push_back(item);
114     }
115     return elems;
116 }
117
118 /*!
119  * \brief Split a string of the form "option=value" into "option" and "value" strings.
120  * This string corresponds to one option and the associated value from the option list 
121  * in the mdrun -device argument.
122  *
123  * \param[in]  s    A string containing an "option=value" pair that needs to be split up.
124  * \param[out] opt  The name of the option.
125  * \param[out] val  Value of the option. 
126  */
127 static void splitOptionValue(const string &s, string &opt, string &val)
128 {
129     size_t eqPos = s.find('=');
130     if (eqPos != string::npos)
131     {
132         opt = s.substr(0, eqPos);
133         if (eqPos != s.length())  val = s.substr(eqPos+1);
134     }
135 }
136
137 /*!
138  * \brief Compare two strings ignoring case.
139  * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
140  * \param[in] s1 String. 
141  * \param[in] s2 String.
142  * \returns      Similarly to the C function strncasecmp(), the return value is an  
143                  integer less than, equal to, or greater than 0 if \p s1 less than, 
144                  identical to, or greater than \p s2.
145  */
146 static gmx_bool isStringEqNCase(const string& s1, const string& s2)
147 {
148     return (gmx_strncasecmp(s1.c_str(), s2.c_str(), max(s1.length(), s2.length())) == 0);
149 }
150
151 /*!
152  * \brief Convert string to upper case.
153  *
154  * \param[in]  s    String to convert to uppercase.
155  * \returns         The given string converted to uppercase.
156  */
157 static string toUpper(const string &s)
158 {
159     string stmp(s);
160     std::transform(stmp.begin(), stmp.end(), stmp.begin(), static_cast < int(*)(int) > (toupper));
161     return stmp;
162 }
163
164 /*! 
165   \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms, 
166   GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
167   GmxOpenMMPlatformOptions#force_dev.  */
168 /* {@ */
169 #define SIZEOF_PLATFORMS    2  // 2
170 #define SIZEOF_MEMTESTS     3 
171 #define SIZEOF_DEVICEIDS    1 
172 #define SIZEOF_FORCE_DEV    2 
173
174 #define SIZEOF_CHECK_COMBRULE 2
175 /* @} */
176
177 /*! Possible platform options in the mdrun -device option. */
178 static const char *devOptStrings[] = { "platform", "deviceid", "memtest", "force-device", "check-combrule" }; 
179
180 /*! Enumerated platform options in the mdrun -device option. */
181 enum devOpt
182 {
183     PLATFORM     = 0,
184     DEVICEID     = 1,
185     MEMTEST      = 2,
186     FORCE_DEVICE = 3
187 };
188
189 /*!
190  * \brief Class to extract and manage the platform options in the mdrun -device option.
191  * 
192  */
193 class GmxOpenMMPlatformOptions
194 {
195 public:
196     GmxOpenMMPlatformOptions(const char *opt);
197     ~GmxOpenMMPlatformOptions() { options.clear(); }
198     string getOptionValue(const string &opt);
199     void remOption(const string &opt);
200     void print();
201 private:
202     void setOption(const string &opt, const string &val);
203
204     map<string, string> options; /*!< Data structure to store the option (name, value) pairs. */
205
206     static const char * const platforms[SIZEOF_PLATFORMS];  /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
207     static const char * const memtests[SIZEOF_MEMTESTS];    /*!< Available types of memory tests, also valid 
208                                                                  any positive integer >=15; size #SIZEOF_MEMTESTS */
209     static const char * const deviceid[SIZEOF_DEVICEIDS];   /*!< Possible values for deviceid option; 
210                                                                  also valid any positive integer; size #SIZEOF_DEVICEIDS */
211     static const char * const force_dev[SIZEOF_FORCE_DEV];  /*!< Possible values for for force-device option; 
212                                                                  size #SIZEOF_FORCE_DEV */
213     static const char * const check_combrule[SIZEOF_CHECK_COMBRULE]; /* XXX temporary debug feature to 
214                                                                       turn off combination rule check */
215 };
216
217 const char * const GmxOpenMMPlatformOptions::platforms[SIZEOF_PLATFORMS]
218                     = {"CUDA", "Reference"};
219                     //= { "Reference", "CUDA" /*,"OpenCL"*/ };
220 const char * const GmxOpenMMPlatformOptions::memtests[SIZEOF_MEMTESTS]
221                     = { "15", "full", "off" };
222 const char * const GmxOpenMMPlatformOptions::deviceid[SIZEOF_DEVICEIDS]
223                     = { "0" };
224 const char * const GmxOpenMMPlatformOptions::force_dev[SIZEOF_FORCE_DEV]
225                     = { "no", "yes" };
226 const char * const GmxOpenMMPlatformOptions::check_combrule[SIZEOF_CHECK_COMBRULE] 
227                     = { "yes", "no" };
228
229 /*!
230  * \brief Contructor.
231  * Takes the option list, parses it, checks the options and their values for validity.
232  * When certain options are not provided by the user, as default value the first item  
233  * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms, 
234  * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
235  * GmxOpenMMPlatformOptions#force_dev). 
236  * \param[in] optionString  Option list part of the mdrun -device parameter.
237  */
238 GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString)
239 {
240     // set default values
241     setOption("platform",       platforms[0]);
242     setOption("memtest",        memtests[0]);
243     setOption("deviceid",       deviceid[0]);
244     setOption("force-device",   force_dev[0]);
245     setOption("check-combrule", check_combrule[0]);
246
247     string opt(optionString);
248
249     // remove all whitespaces
250     opt.erase(remove_if(opt.begin(), opt.end(), ::isspace), opt.end());
251     // tokenize around ","-s
252     vector<string> tokens = split(opt, ',');
253
254     for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
255     {
256         string opt = "", val = "";
257         splitOptionValue(*it, opt, val);
258
259         if (isStringEqNCase(opt, "platform"))
260         {
261             /* no check, this will fail if platform does not exist when we try to set it */
262             setOption(opt, val);
263             continue;
264         }
265
266         if (isStringEqNCase(opt, "memtest"))
267         {
268             /* the value has to be an integer >15(s) or "full" OR "off" */
269             if (!isStringEqNCase(val, "full") && !isStringEqNCase(val, "off")) 
270             {
271                 int secs;
272                 if (!from_string<int>(secs, val, std::dec))
273                 {
274                     gmx_fatal(FARGS, "Invalid value for option memtest option: \"%s\"!", val.c_str());
275                 }
276                 if (secs < 15)
277                 {
278                     gmx_fatal(FARGS, "Incorrect value for memtest option (%d). "
279                             "Memtest needs to run for at least 15s!", secs);
280                 }
281             }
282             setOption(opt, val);
283             continue;
284         }
285
286         if (isStringEqNCase(opt, "deviceid"))
287         {
288             int id;
289             if (!from_string<int>(id, val, std::dec) )
290             {
291                 gmx_fatal(FARGS, "Invalid device id: \"%s\"!", val.c_str());
292             }
293             setOption(opt, val);
294             continue;
295         }
296
297         if (isStringEqNCase(opt, "force-device"))
298         {
299             /* */
300             if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
301             {
302                 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
303             }
304             setOption(opt, val);
305             continue;
306         }
307
308         if (isStringEqNCase(opt, "check-combrule"))
309         {
310             /* */
311             if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
312             {
313                 gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
314             }
315             setOption(opt, val);
316             continue;
317         }
318
319
320         // if we got till here something went wrong
321         gmx_fatal(FARGS, "Invalid OpenMM platform option: \"%s\"!", (*it).c_str());
322     }
323 }
324
325
326 /*!
327  * \brief Getter function.
328  * \param[in] opt   Name of the option.
329  * \returns         Returns the value associated to an option. 
330  */
331 string GmxOpenMMPlatformOptions::getOptionValue(const string &opt)
332 {
333         map<string, string> :: const_iterator it = options.find(toUpper(opt));
334         if (it != options.end())
335     {
336                 return it->second;
337     }
338     else
339     {
340         return NULL;
341     }
342 }
343
344 /*!
345  * \brief Setter function - private, only used from contructor.
346  * \param[in] opt   Name of the option.
347  * \param[in] val   Value for the option. 
348  */
349 void GmxOpenMMPlatformOptions::setOption(const string &opt, const string &val)
350 {
351     options[toUpper(opt)] = val;
352 }
353
354 /*!
355  * \brief Removes an option with its value from the map structure. If the option 
356  * does not exist, returns without any action.
357  * \param[in] opt   Name of the option.
358  */
359 void GmxOpenMMPlatformOptions::remOption(const string &opt) 
360
361     options.erase(toUpper(opt)); 
362 }
363
364 /*!
365  * \brief Print option-value pairs to a file (debugging function). 
366  */
367 void GmxOpenMMPlatformOptions::print()
368 {
369     cout << ">> Platform options: " << endl 
370          << ">> platform     = " << getOptionValue("platform") << endl
371          << ">> deviceID     = " << getOptionValue("deviceid") << endl
372          << ">> memtest      = " << getOptionValue("memtest") << endl
373          << ">> force-device = " << getOptionValue("force-device") << endl;
374 }
375
376 /*!
377  * \brief Container for OpenMM related data structures that represent the bridge 
378  *        between the Gromacs data-structures and the OpenMM library and is but it's 
379  *        only passed through the API functions as void to disable direct access. 
380  */
381 class OpenMMData
382 {
383 public:
384     System* system;      /*! The system to simulate. */
385     Context* context;   /*! The OpenMM context in which the simulation is carried out. */
386     Integrator* integrator; /*! The integrator used in the simulation. */
387     gmx_bool removeCM;          /*! If \true remove venter of motion, false otherwise. */
388     GmxOpenMMPlatformOptions *platformOpt; /*! Platform options. */
389 };
390
391 /*!
392  *  \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
393  *  \param[in] fplog    Pointer to gromacs log file.
394  *  \param[in] devId    Device id of the GPU to run the test on. 
395                         Note: as OpenMM previously creates the context,for now this is always -1.
396  *  \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in 
397  *                      stdout messages/log between memtest carried out before and after simulation.
398  *  \param[in] opt      Pointer to platform options object.
399  */
400 static void runMemtest(FILE* fplog, int devId, const char* pre_post, GmxOpenMMPlatformOptions *opt)
401 {
402     char        strout_buf[STRLEN];
403     int         which_test;
404     int         res = 0;
405     string      s = opt->getOptionValue("memtest");
406     const char  *test_type = s.c_str();
407
408     if (!gmx_strcasecmp(test_type, "off"))
409     {
410         which_test = 0;
411     }
412     else
413     {
414         if (!gmx_strcasecmp(test_type, "full"))
415         {
416             which_test = 2;
417         }
418         else
419         {
420             from_string<int>(which_test, test_type, std::dec);
421         }
422     }
423
424     if (which_test < 0) 
425     {
426         gmx_fatal(FARGS, "Amount of seconds for memetest is negative (%d). ", which_test);
427     }
428
429     switch (which_test)
430     {
431         case 0: /* no memtest */
432             sprintf(strout_buf, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
433                 "incorrect results!", pre_post);
434             fprintf(fplog, "%s\n", strout_buf);
435             gmx_warning(strout_buf);
436             break; /* case 0 */
437
438         case 1: /* quick memtest */
439             fprintf(fplog,  "%s-simulation %s GPU memtest in progress...\n", pre_post, test_type);
440             fprintf(stdout, "\n%s-simulation %s GPU memtest in progress...", pre_post, test_type);
441             fflush(fplog);
442             fflush(stdout);
443             res = do_quick_memtest(devId);
444             break; /* case 1 */
445
446         case 2: /* full memtest */
447             fprintf(fplog,  "%s-simulation %s memtest in progress...\n", pre_post, test_type);
448             fprintf(stdout, "\n%s-simulation %s memtest in progress...", pre_post, test_type);
449             fflush(fplog);
450             fflush(stdout);
451             res = do_full_memtest(devId);
452             break; /* case 2 */
453
454         default: /* timed memtest */
455             fprintf(fplog,  "%s-simulation ~%ds memtest in progress...\n", pre_post, which_test);
456             fprintf(stdout, "\n%s-simulation ~%ds memtest in progress...", pre_post, which_test);
457             fflush(fplog);
458             fflush(stdout);
459             res = do_timed_memtest(devId, which_test);
460         }
461
462         if (which_test != 0)
463         {
464             if (res != 0)
465             {
466                 gmx_fatal(FARGS, MEM_ERR_MSG(pre_post));
467             }
468             else
469             {
470                 fprintf(fplog,  "Memory test completed without errors.\n");
471                 fflush(fplog);
472                 fprintf(stdout, "done, no errors detected\n");
473                 fflush(stdout);           
474             }
475         }
476 }
477
478 /*!
479  * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
480  * 
481  * \param[in] c12
482  * \param[in] c6
483  * \param[out] sigma 
484  * \param[out] epsilon
485  */
486 static void convert_c_12_6(double c12, double c6, double *sigma, double *epsilon)
487 {
488     if (c12 == 0 && c6 == 0)
489     {
490         *epsilon    = 0.0;        
491         *sigma      = 1.0;
492     }
493     else if (c12 > 0 && c6 > 0)
494     {
495         *epsilon    = (c6*c6)/(4.0*c12);
496         *sigma      = pow(c12/c6, 1.0/6.0);
497     }
498     else 
499     {
500         gmx_fatal(FARGS,"OpenMM only supports c6 > 0 and c12 > 0 or c6 = c12 = 0.");
501     } 
502 }
503
504 /*!
505  * \brief Does gromacs option checking.
506  *
507  * Checks the gromacs mdp options for features unsupported in OpenMM, case in which 
508  * interrupts the execution. It also warns the user about pecularities of OpenMM 
509  * implementations.
510  * \param[in] fplog         Gromacs log file pointer.
511  * \param[in] ir            Gromacs input parameters, see ::t_inputrec
512  * \param[in] top           Gromacs node local topology, \see gmx_localtop_t
513  * \param[in] state         Gromacs state structure \see ::t_state
514  * \param[in] mdatoms       Gromacs atom parameters, \see ::t_mdatoms
515  * \param[in] fr            \see ::t_forcerec
516  * \param[in] state         Gromacs systems state, \see ::t_state
517  */
518 static void checkGmxOptions(FILE* fplog, GmxOpenMMPlatformOptions *opt,
519                             t_inputrec *ir, gmx_localtop_t *top,
520                             t_forcerec *fr, t_state *state)
521 {
522     char    warn_buf[STRLEN];
523     int     i, j, natoms;
524     double  c6, c12;
525     double  sigma_ij=0, sigma_ji=0, sigma_ii=0, sigma_jj=0, sigma_comb;
526     double  eps_ij=0, eps_ji=0, eps_ii=0, eps_jj=0, eps_comb;
527
528     /* Abort if unsupported critical options are present */
529
530     /* Integrator */
531     if (ir->eI ==  eiMD)
532     {
533         gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
534     }
535
536     if (    (ir->eI !=  eiMD)   &&
537             (ir->eI !=  eiVV)   &&
538             (ir->eI !=  eiVVAK) &&
539             (ir->eI !=  eiSD1)  &&
540             (ir->eI !=  eiSD2)  &&
541             (ir->eI !=  eiBD) )
542     {
543         gmx_fatal(FARGS, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
544     }
545
546     /* Electroctstics */
547     if (   !(ir->coulombtype == eelPME   ||
548              EEL_RF(ir->coulombtype)     ||
549              ir->coulombtype == eelRF    ||
550              ir->coulombtype == eelEWALD ||
551              // no-cutoff
552              (ir->coulombtype == eelCUT && ir->rcoulomb == 0 &&  ir->rvdw == 0) ||
553              // we could have cut-off combined with GBSA (openmm will use RF)
554              ir->implicit_solvent == eisGBSA)   )
555     {
556         gmx_fatal(FARGS,"OpenMM supports only the following methods for electrostatics: "
557                 "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
558     }
559
560     if (EEL_RF(ir->coulombtype) && ir->epsilon_rf != 0)
561     {
562         // openmm has epsilon_rf=inf hard-coded
563         gmx_warning("OpenMM will use a Reaction-Field epsilon of infinity instead of %g.",ir->epsilon_rf);
564     }
565
566     if (ir->etc != etcNO &&
567         ir->eI  != eiSD1 &&
568         ir->eI  != eiSD2 &&
569         ir->eI  != eiBD )
570     {
571         gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
572     }
573
574     if (ir->implicit_solvent == eisGBSA &&
575         ir->gb_algorithm != egbOBC  )
576     {
577         gmx_warning("OpenMM does not support the specified algorithm for Generalized Born, will use OBC instead.");
578     }
579
580     if (ir->opts.ngtc > 1)
581         gmx_fatal(FARGS,"OpenMM does not support multiple temperature coupling groups.");
582
583     if (ir->epc != epcNO)
584         gmx_warning("OpenMM supports only Monte Carlo barostat for pressure coupling.");
585
586     if (ir->opts.annealing[0])
587         gmx_fatal(FARGS,"OpenMM does not support simulated annealing.");
588     
589     if (top->idef.il[F_CONSTR].nr > 0 && ir->eConstrAlg != econtSHAKE)
590         gmx_warning("OpenMM provides contraints as a combination "
591                     "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
592                     "by the \"shake_tol\" option.");
593
594     if (ir->nwall != 0)
595         gmx_fatal(FARGS,"OpenMM does not support walls.");
596
597     if (ir->ePull != epullNO)
598         gmx_fatal(FARGS,"OpenMM does not support pulling.");
599
600     /* check for interaction types */
601     for (i = 0; i < F_EPOT; i++)
602     {
603         if (!(i == F_CONSTR ||
604             i == F_SETTLE   ||
605             i == F_BONDS    ||            
606             i == F_HARMONIC ||
607             i == F_UREY_BRADLEY ||
608             i == F_ANGLES   ||
609             i == F_PDIHS    ||
610             i == F_RBDIHS   ||
611             i == F_PIDIHS   ||
612             i == F_IDIHS    ||
613             i == F_LJ14     ||
614             i == F_GB12     || /* The GB parameters are hardcoded both in */
615             i == F_GB13     || /* Gromacs and OpenMM */
616             i == F_GB14   ) &&
617             top->idef.il[i].nr > 0)
618         {
619             gmx_fatal(FARGS, "OpenMM does not support (some) of the provided interaction " 
620                     "type(s) (%s) ", interaction_function[i].longname);
621         }
622     }
623
624     if (ir->efep != efepNO)
625         gmx_fatal(FARGS,"OpenMM does not support free energy calculations.");
626
627     if (ir->opts.ngacc > 1)
628         gmx_fatal(FARGS,"OpenMM does not support non-equilibrium MD (accelerated groups).");
629
630     if (IR_ELEC_FIELD(*ir))
631         gmx_fatal(FARGS,"OpenMM does not support electric fields.");
632
633     if (ir->bQMMM)
634         gmx_fatal(FARGS,"OpenMM does not support QMMM calculations.");
635
636     if (ir->rcoulomb != ir->rvdw)
637         gmx_fatal(FARGS,"OpenMM uses a single cutoff for both Coulomb "
638                   "and VdW interactions. Please set rcoulomb equal to rvdw.");
639     
640     if (EEL_FULL(ir->coulombtype))
641     {
642         if (ir->ewald_geometry == eewg3DC)
643             gmx_fatal(FARGS,"OpenMM supports only Ewald 3D geometry.");
644         if (ir->epsilon_surface != 0)
645             gmx_fatal(FARGS,"OpenMM does not support dipole correction in Ewald summation.");
646     }
647
648     if (TRICLINIC(state->box))        
649     {
650         gmx_fatal(FARGS,"OpenMM does not support triclinic unit cells.");
651     }
652
653     /* XXX this is just debugging code to disable the combination rule check */
654     if ( isStringEqNCase(opt->getOptionValue("check-combrule"), "yes") )
655     {
656     /* As OpenMM by default uses hardcoded combination rules 
657        sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j)
658        we need to check whether the force field params obey this 
659        and if not, we can't use this force field so we exit 
660        grace-fatal-fully. */
661     real *nbfp = fr->nbfp;
662     natoms = fr->ntype;
663     if (debug) 
664     {   
665         fprintf(debug, ">> Atom parameters: <<\n%10s%5s %5s %5s %5s COMB\n", 
666                 "", "i-j", "j-i", "i-i", "j-j");
667     }
668     /* loop over all i-j atom pairs and verify if 
669        sigma_ij = sigma_ji = sigma_comb and eps_ij = eps_ji = eps_comb */
670     for (i = 0; i < natoms; i++)
671     {
672         /* i-i */
673         /* nbfp now includes the 6.0/12.0 prefactors to save flops in kernels */
674         c12 = C12(nbfp, natoms, i, i)/12.0;
675         c6  = C6(nbfp,  natoms, i, i)/6.0;
676         convert_c_12_6(c12, c6, &sigma_ii, &eps_ii);
677
678         for (j = 0; j < i; j++)
679         {
680             /* i-j */
681             c12 = C12(nbfp, natoms, i, j)/12.0;
682             c6  = C6(nbfp,  natoms, i, j)/6.0;
683             convert_c_12_6(c12, c6, &sigma_ij, &eps_ij);
684             /* j-i */
685             c12 = C12(nbfp, natoms, j, i)/12.0;
686             c6  = C6(nbfp,  natoms, j, i)/6.0;
687             convert_c_12_6(c12, c6, &sigma_ji, &eps_ji);
688             /* j-j */
689             c12 = C12(nbfp, natoms, j, j)/12.0;
690             c6  = C6(nbfp,  natoms, j, j)/6.0;
691             convert_c_12_6(c12, c6, &sigma_jj, &eps_jj);
692             /* OpenMM hardcoded combination rules */
693             sigma_comb = COMBRULE_SIGMA(sigma_ii, sigma_jj);
694             eps_comb = COMBRULE_EPS(eps_ii, eps_jj);
695   
696             if (debug)
697             {
698                 fprintf(debug, "i=%-3d j=%-3d", i, j);
699                 fprintf(debug, "%-11s", "sigma");
700                 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",  
701                         sigma_ij, sigma_ji, sigma_ii, sigma_jj, sigma_comb);
702                 fprintf(debug, "%11s%-11s", "", "epsilon");
703                 fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n", 
704                         eps_ij, eps_ji, eps_ii, eps_jj, eps_comb);
705             }
706
707             /* check the values against the rule used by omm */
708             if((fabs(eps_ij) > COMBRULE_CHK_TOL && 
709                 fabs(eps_ji) > COMBRULE_CHK_TOL) &&
710                (fabs(sigma_comb - sigma_ij) > COMBRULE_CHK_TOL ||
711                fabs(sigma_comb - sigma_ji) > COMBRULE_CHK_TOL ||
712                fabs(eps_comb - eps_ij) > COMBRULE_CHK_TOL ||
713                fabs(eps_comb - eps_ji) > COMBRULE_CHK_TOL ))
714             {
715                 gmx_fatal(FARGS,
716                         "The combination rules of the used force-field do not "
717                         "match the one supported by OpenMM:  "
718                         "sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j). "
719                         "Switch to a force-field that uses these rules in order to "
720                         "simulate this system using OpenMM.\n");                        
721             }
722         }
723     }
724     if (debug) { fprintf(debug, ">><<\n\n"); }
725
726     /* if we got here, log that everything is fine */
727     if (debug)
728     {
729         fprintf(debug, ">> The combination rule of the used force matches the one used by OpenMM.\n");
730     }
731     fprintf(fplog, "The combination rule of the used force field matches the one used by OpenMM.\n");   
732
733     } /* if (are we checking the combination rules) ... */
734 }
735
736
737 /*!
738  * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to 
739  * the OpenMMData.
740  * 
741  * Various gromacs data structures are passed that contain the parameters, state and 
742  * other porperties of the system to simulate. These serve as input for initializing 
743  * OpenMM. Besides, a set of misc action are taken:
744  *  - OpenMM plugins are loaded;
745  *  - platform options in \p platformOptStr are parsed and checked; 
746  *  - Gromacs parameters are checked for OpenMM support and consistency;
747  *  - after the OpenMM is initialized memtest executed in the same GPU context.
748  * 
749  * \param[in] fplog             Gromacs log file handler.
750  * \param[in] platformOptStr    Platform option string. 
751  * \param[in] ir                The Gromacs input parameters, see ::t_inputrec
752  * \param[in] top_global        Gromacs system toppology, \see ::gmx_mtop_t
753  * \param[in] top               Gromacs node local topology, \see gmx_localtop_t
754  * \param[in] mdatoms           Gromacs atom parameters, \see ::t_mdatoms
755  * \param[in] fr                \see ::t_forcerec
756  * \param[in] state             Gromacs systems state, \see ::t_state
757  * \returns                     Pointer to a 
758  * 
759  */
760 void* openmm_init(FILE *fplog, const char *platformOptStr,
761                   t_inputrec *ir,
762                   gmx_mtop_t *top_global, gmx_localtop_t *top,
763                   t_mdatoms *mdatoms, t_forcerec *fr, t_state *state)
764 {
765
766     char warn_buf[STRLEN];
767     static gmx_bool hasLoadedPlugins = false;
768     string usedPluginDir;
769     int devId;
770
771     try
772     {
773         if (!hasLoadedPlugins)
774         {
775             vector<string> loadedPlugins;
776             /*  Look for OpenMM plugins at various locations (listed in order of priority):
777                 - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
778                 - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
779                 - at the default location assumed by OpenMM
780             */
781             /* env var */
782             char *pluginDir = getenv("OPENMM_PLUGIN_DIR");
783             trim(pluginDir);
784             /* no env var or empty */
785             if (pluginDir != NULL && *pluginDir != '\0')
786             {
787                 loadedPlugins = Platform::loadPluginsFromDirectory(pluginDir);
788                 if (!loadedPlugins.empty())
789                 {
790                     hasLoadedPlugins = true;
791                     usedPluginDir = pluginDir;
792                 }
793                 else
794                 {
795                     gmx_fatal(FARGS, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
796                               "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!", 
797                               pluginDir);
798                 }
799             }
800
801             /* macro set at build time  */
802 #ifdef OPENMM_PLUGIN_DIR
803             if (!hasLoadedPlugins)
804             {
805                 loadedPlugins = Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR);
806                 if (!loadedPlugins.empty())
807                 {
808                     hasLoadedPlugins = true;
809                     usedPluginDir = OPENMM_PLUGIN_DIR;
810                 }
811             }
812 #endif
813             /* default loocation */
814             if (!hasLoadedPlugins)
815             {
816                 loadedPlugins = Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
817                 if (!loadedPlugins.empty())
818                 {
819                     hasLoadedPlugins = true;
820                     usedPluginDir = Platform::getDefaultPluginsDirectory();
821                 }
822             }
823
824             /* if there are still no plugins loaded there won't be any */
825             if (!hasLoadedPlugins)
826             {
827                 gmx_fatal(FARGS, "No OpenMM plugins were found! You can provide the"
828                           " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir);
829             }
830
831             fprintf(fplog, "\nOpenMM plugins loaded from directory %s:\t", usedPluginDir.c_str());
832             for (int i = 0; i < (int)loadedPlugins.size(); i++)
833             {
834                 fprintf(fplog, "%s, ", loadedPlugins[i].c_str());
835             }
836             fprintf(fplog, "\n");
837         }
838
839         /* parse option string */
840         GmxOpenMMPlatformOptions *opt = new GmxOpenMMPlatformOptions(platformOptStr);
841         devId = atoi(opt->getOptionValue("deviceid").c_str());
842
843         if (debug)
844         {
845             opt->print();
846         }
847
848         /* check wheter Gromacs options compatibility with OpenMM */
849         checkGmxOptions(fplog, opt, ir, top, fr, state);
850
851         /* Create the system. */
852         const t_idef& idef = top->idef;
853         const int numAtoms = top_global->natoms;
854         const int numConstraints = idef.il[F_CONSTR].nr/3;
855         const int numSettle = idef.il[F_SETTLE].nr/2;
856         const int numBonds = idef.il[F_BONDS].nr/3;
857         const int numHarmonic = idef.il[F_HARMONIC].nr/3;
858         const int numUB = idef.il[F_UREY_BRADLEY].nr/4;
859         const int numAngles = idef.il[F_ANGLES].nr/4;
860         const int numPeriodic = idef.il[F_PDIHS].nr/5;
861         const int numPeriodicImproper = idef.il[F_PIDIHS].nr/5;
862         const int numRB = idef.il[F_RBDIHS].nr/5;
863         const int numImproperDih = idef.il[F_IDIHS].nr/5;
864         const int num14 = idef.il[F_LJ14].nr/3;
865         System* sys = new System();
866         if (ir->nstcomm > 0)
867             sys->addForce(new CMMotionRemover(ir->nstcomm));
868
869         /* Set bonded force field terms. */
870
871                 /* 
872                  * CUDA platform currently doesn't support more than one
873                  * instance of a force object, so we pack all forces that
874                  * use the same form into one.
875                 */
876
877         const int* bondAtoms = (int*) idef.il[F_BONDS].iatoms;
878         HarmonicBondForce* bondForce = new HarmonicBondForce();
879         sys->addForce(bondForce);
880         int offset = 0;
881         for (int i = 0; i < numBonds; ++i)
882         {
883             int type = bondAtoms[offset++];
884             int atom1 = bondAtoms[offset++];
885             int atom2 = bondAtoms[offset++];
886             bondForce->addBond(atom1, atom2,
887                                idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
888         }
889
890         const int* harmonicAtoms = (int*) idef.il[F_HARMONIC].iatoms;
891         offset = 0;
892         for (int i = 0; i < numHarmonic; ++i)
893         {
894             int type = harmonicAtoms[offset++];
895             int atom1 = harmonicAtoms[offset++];
896             int atom2 = harmonicAtoms[offset++];
897             bondForce->addBond(atom1, atom2,
898                                idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
899         }
900
901                 /* Set the angle force field terms */
902         const int* angleAtoms = (int*) idef.il[F_ANGLES].iatoms;
903         HarmonicAngleForce* angleForce = new HarmonicAngleForce();
904         sys->addForce(angleForce);
905         offset = 0;
906         for (int i = 0; i < numAngles; ++i)
907         {
908             int type = angleAtoms[offset++];
909             int atom1 = angleAtoms[offset++];
910             int atom2 = angleAtoms[offset++];
911             int atom3 = angleAtoms[offset++];
912             angleForce->addAngle(atom1, atom2, atom3, 
913                     idef.iparams[type].harmonic.rA*M_PI/180.0, idef.iparams[type].harmonic.krA);
914         }
915
916         /* Urey-Bradley includes both the angle and bond potential for 1-3 interactions */
917         const int* ubAtoms = (int*) idef.il[F_UREY_BRADLEY].iatoms;
918                 /* HarmonicBondForce* ubBondForce = new HarmonicBondForce(); */
919                 /*  HarmonicAngleForce* ubAngleForce = new HarmonicAngleForce(); */
920         /* sys->addForce(ubBondForce); */
921         /* sys->addForce(ubAngleForce); */
922         offset = 0;
923         for (int i = 0; i < numUB; ++i)
924         {
925             int type = ubAtoms[offset++];
926             int atom1 = ubAtoms[offset++];
927             int atom2 = ubAtoms[offset++];
928             int atom3 = ubAtoms[offset++];
929             /* ubBondForce->addBond(atom1, atom3, */
930             bondForce->addBond(atom1, atom3,
931                                idef.iparams[type].u_b.r13A, idef.iparams[type].u_b.kUBA);
932             /* ubAngleForce->addAngle(atom1, atom2, atom3, */ 
933             angleForce->addAngle(atom1, atom2, atom3, 
934                     idef.iparams[type].u_b.thetaA*M_PI/180.0, idef.iparams[type].u_b.kthetaA);
935         }
936
937                 /* Set proper dihedral terms */
938         const int* periodicAtoms = (int*) idef.il[F_PDIHS].iatoms;
939         PeriodicTorsionForce* periodicForce = new PeriodicTorsionForce();
940         sys->addForce(periodicForce);
941         offset = 0;
942         for (int i = 0; i < numPeriodic; ++i)
943         {
944             int type = periodicAtoms[offset++];
945             int atom1 = periodicAtoms[offset++];
946             int atom2 = periodicAtoms[offset++];
947             int atom3 = periodicAtoms[offset++];
948             int atom4 = periodicAtoms[offset++];
949             periodicForce->addTorsion(atom1, atom2, atom3, atom4,
950                                       idef.iparams[type].pdihs.mult,
951                                       idef.iparams[type].pdihs.phiA*M_PI/180.0, 
952                                       idef.iparams[type].pdihs.cpA);
953         }
954
955                 /* Set improper dihedral terms that are represented by a periodic function (as in AMBER FF) */
956         const int* periodicImproperAtoms = (int*) idef.il[F_PIDIHS].iatoms;
957         /* PeriodicTorsionForce* periodicImproperForce = new PeriodicTorsionForce(); */
958         /* sys->addForce(periodicImproperForce); */
959         offset = 0;
960         for (int i = 0; i < numPeriodicImproper; ++i)
961         {
962             int type = periodicImproperAtoms[offset++];
963             int atom1 = periodicImproperAtoms[offset++];
964             int atom2 = periodicImproperAtoms[offset++];
965             int atom3 = periodicImproperAtoms[offset++];
966             int atom4 = periodicImproperAtoms[offset++];
967             /* periodicImproperForce->addTorsion(atom1, atom2, atom3, atom4, */
968             periodicForce->addTorsion(atom1, atom2, atom3, atom4,
969                                       idef.iparams[type].pdihs.mult,
970                                       idef.iparams[type].pdihs.phiA*M_PI/180.0,
971                                       idef.iparams[type].pdihs.cpA);
972         }
973
974         /* Ryckaert-Bellemans dihedrals */
975         const int* rbAtoms = (int*) idef.il[F_RBDIHS].iatoms;
976         RBTorsionForce* rbForce = new RBTorsionForce();
977         sys->addForce(rbForce);
978         offset = 0;
979         for (int i = 0; i < numRB; ++i)
980         {
981             int type = rbAtoms[offset++];
982             int atom1 = rbAtoms[offset++];
983             int atom2 = rbAtoms[offset++];
984             int atom3 = rbAtoms[offset++];
985             int atom4 = rbAtoms[offset++];
986             rbForce->addTorsion(atom1, atom2, atom3, atom4,
987                                 idef.iparams[type].rbdihs.rbcA[0], idef.iparams[type].rbdihs.rbcA[1],
988                                 idef.iparams[type].rbdihs.rbcA[2], idef.iparams[type].rbdihs.rbcA[3],
989                                 idef.iparams[type].rbdihs.rbcA[4], idef.iparams[type].rbdihs.rbcA[5]);
990         }
991
992                 /* Set improper dihedral terms (as in CHARMM FF) */
993         const int* improperDihAtoms = (int*) idef.il[F_IDIHS].iatoms;
994                 CustomTorsionForce* improperDihForce = new CustomTorsionForce("2.0*k*asin(sin((theta-theta0)/2))^2");
995         sys->addForce(improperDihForce);
996                 improperDihForce->addPerTorsionParameter("k");
997                 improperDihForce->addPerTorsionParameter("theta0");
998                 vector<double> improperDihParameters(2);
999         offset = 0;
1000         for (int i = 0; i < numImproperDih; ++i)
1001         {
1002             int type = improperDihAtoms[offset++];
1003             int atom1 = improperDihAtoms[offset++];
1004             int atom2 = improperDihAtoms[offset++];
1005             int atom3 = improperDihAtoms[offset++];
1006             int atom4 = improperDihAtoms[offset++];
1007                         improperDihParameters[0] = idef.iparams[type].harmonic.krA;
1008                         improperDihParameters[1] = idef.iparams[type].harmonic.rA*M_PI/180.0;
1009             improperDihForce->addTorsion(atom1, atom2, atom3, atom4,
1010                                 improperDihParameters);
1011         }
1012
1013         /* Set nonbonded parameters and masses. */
1014         int ntypes = fr->ntype;
1015         int* types = mdatoms->typeA;
1016         real* nbfp = fr->nbfp;
1017         real* charges = mdatoms->chargeA;
1018         real* masses = mdatoms->massT;
1019         NonbondedForce* nonbondedForce = new NonbondedForce();
1020         sys->addForce(nonbondedForce);
1021         
1022         switch (ir->ePBC)
1023         {
1024         case epbcNONE:
1025             if (ir->rcoulomb == 0)
1026             {
1027                 nonbondedForce->setNonbondedMethod(NonbondedForce::NoCutoff);
1028             }
1029             else
1030             {
1031                 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
1032             }
1033             break;
1034         case epbcXYZ:
1035             switch (ir->coulombtype)
1036             {
1037             case eelCUT:
1038             case eelRF:
1039             case eelGRF:
1040             case eelRF_NEC:
1041             case eelRF_ZERO:
1042                 nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
1043                 break;
1044
1045             case eelEWALD:
1046                 nonbondedForce->setNonbondedMethod(NonbondedForce::Ewald);
1047                 break;
1048
1049             case eelPME:
1050                 nonbondedForce->setNonbondedMethod(NonbondedForce::PME);
1051                 break;
1052
1053             default:
1054                 gmx_fatal(FARGS,"Internal error: you should not see this message, it means that the"
1055                           "electrosatics option check failed. Please report this error!");
1056             }        
1057             sys->setDefaultPeriodicBoxVectors(Vec3(state->box[0][0], 0, 0),
1058                                        Vec3(0, state->box[1][1], 0), Vec3(0, 0, state->box[2][2]));                    
1059             nonbondedForce->setCutoffDistance(ir->rcoulomb);
1060            
1061             break;
1062         default:            
1063             gmx_fatal(FARGS,"OpenMM supports only full periodic boundary conditions "
1064                               "(pbc = xyz), or none (pbc = no).");
1065         }
1066
1067
1068         /* Fix for PME and Ewald error tolerance 
1069          *
1070                  *  OpenMM uses approximate formulas to calculate the Ewald parameter:
1071                  *  alpha = (1.0/cutoff)*sqrt(-log(2.0*tolerlance));
1072                  *  and the grid spacing for PME:
1073                  *  gridX = ceil(2*alpha*box[0][0]/3*(pow(tol, 0.2)))
1074                  *  gridY = ceil(2*alpha*box[1][1]/3*(pow(tol, 0.2)));
1075                  *  gridZ = ceil(2*alpha*box[2][2]/3*(pow(tol, 0.2)));
1076                  *
1077                  *  
1078                  *  If the default ewald_rtol=1e-5 is used we silently adjust the value to the 
1079                  *  OpenMM default of 5e-4 otherwise a warning is issued about the action taken. 
1080                  *
1081                 */
1082         double corr_ewald_rtol = 50.0 * ir->ewald_rtol;
1083         if ((ir->ePBC == epbcXYZ) && 
1084             (ir->coulombtype == eelEWALD || ir->coulombtype == eelPME))
1085         {
1086             if (debug)
1087             {
1088                 fprintf(debug, ">> ewald_rtol = %e (corrected = %e) \n",
1089                     ir->ewald_rtol, corr_ewald_rtol);
1090             }
1091
1092             if (fabs(ir->ewald_rtol - 1e-5) > 1e-10)
1093             {
1094                 gmx_warning("OpenMM uses the ewald_rtol parameter with approximate formulas "
1095                         "to calculate the alpha and grid spacing parameters of the Ewald "
1096                         "and PME methods. This tolerance need to be corrected in order to get "
1097                         "settings close to the ones used in GROMACS. Although the internal correction "
1098                         "should work for any reasonable value of ewald_rtol, using values other than "
1099                         "the default 1e-5 might cause incorrect behavior.");
1100
1101                 if (corr_ewald_rtol > 1)
1102                 {
1103                     gmx_fatal(FARGS, "The ewald_rtol accuracy term is >1 after the "
1104                             "adjustment for OpenMM (%e)", corr_ewald_rtol);
1105                 }
1106             }
1107             nonbondedForce->setEwaldErrorTolerance(corr_ewald_rtol);
1108         }
1109
1110         for (int i = 0; i < numAtoms; ++i)
1111         {
1112             /* nbfp now includes the 6.0/12.0 derivative prefactors to save flops in kernels*/
1113             double c12 = nbfp[types[i]*2*ntypes+types[i]*2+1]/12.0;
1114             double c6 = nbfp[types[i]*2*ntypes+types[i]*2]/6.0;
1115             double sigma=0.0, epsilon=0.0;
1116             convert_c_12_6(c12, c6, &sigma, &epsilon);
1117             nonbondedForce->addParticle(charges[i], sigma, epsilon);
1118             sys->addParticle(masses[i]);
1119         }
1120
1121         // Build a table of all exclusions.
1122         vector<set<int> > exclusions(numAtoms);
1123         for (int i = 0; i < numAtoms; i++)
1124         {
1125             int start = top->excls.index[i];
1126             int end = top->excls.index[i+1];
1127             for (int j = start; j < end; j++)
1128                 exclusions[i].insert(top->excls.a[j]);
1129         }
1130
1131         // Record the 1-4 interactions, and remove them from the list of exclusions.
1132         const int* nb14Atoms = (int*) idef.il[F_LJ14].iatoms;
1133         offset = 0;
1134         for (int i = 0; i < num14; ++i)
1135         {
1136             int type = nb14Atoms[offset++];
1137             int atom1 = nb14Atoms[offset++];
1138             int atom2 = nb14Atoms[offset++];
1139             double sigma=0, epsilon=0;
1140             convert_c_12_6(idef.iparams[type].lj14.c12A, 
1141                     idef.iparams[type].lj14.c6A,
1142                     &sigma, &epsilon);
1143             nonbondedForce->addException(atom1, atom2,
1144                                          fr->fudgeQQ*charges[atom1]*charges[atom2], sigma, epsilon);
1145             exclusions[atom1].erase(atom2);
1146             exclusions[atom2].erase(atom1);
1147         }
1148
1149         // Record exclusions.
1150         for (int i = 0; i < numAtoms; i++)
1151         {
1152             for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
1153             {
1154                 if (i < *iter)
1155                 {
1156                     nonbondedForce->addException(i, *iter, 0.0, 1.0, 0.0);
1157                 }
1158             }
1159         }
1160
1161         // Add GBSA if needed.
1162         if (ir->implicit_solvent == eisGBSA)
1163         {
1164             gmx_warning("The OBC scale factors alpha, beta and gamma are hardcoded in OpenMM with the default Gromacs values.");
1165             t_atoms atoms       = gmx_mtop_global_atoms(top_global);
1166             GBSAOBCForce* gbsa  = new GBSAOBCForce();
1167
1168             sys->addForce(gbsa);
1169             gbsa->setSoluteDielectric(ir->epsilon_r);
1170             gbsa->setSolventDielectric(ir->gb_epsilon_solvent);
1171             gbsa->setCutoffDistance(nonbondedForce->getCutoffDistance());
1172             if (nonbondedForce->getNonbondedMethod() == NonbondedForce::NoCutoff)
1173                 gbsa->setNonbondedMethod(GBSAOBCForce::NoCutoff);
1174             else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic)
1175                 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
1176             else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffPeriodic)
1177                 gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
1178             else
1179                 gmx_fatal(FARGS,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
1180
1181             for (int i = 0; i < numAtoms; ++i)
1182             {
1183                 gbsa->addParticle(charges[i],
1184                                   top_global->atomtypes.gb_radius[atoms.atom[i].type],
1185                                   top_global->atomtypes.S_hct[atoms.atom[i].type]);
1186             }
1187             free_t_atoms(&atoms, FALSE);
1188         }
1189
1190         // Set constraints.
1191         const int* constraintAtoms = (int*) idef.il[F_CONSTR].iatoms;
1192         offset = 0;
1193         for (int i = 0; i < numConstraints; ++i)
1194         {
1195             int type = constraintAtoms[offset++];
1196             int atom1 = constraintAtoms[offset++];
1197             int atom2 = constraintAtoms[offset++];
1198             sys->addConstraint(atom1, atom2, idef.iparams[type].constr.dA);
1199         }
1200         const int* settleAtoms = (int*) idef.il[F_SETTLE].iatoms;
1201         offset = 0;
1202         for (int i = 0; i < numSettle; ++i)
1203         {
1204             int type = settleAtoms[offset++];
1205             int oxygen = settleAtoms[offset++];
1206             sys->addConstraint(oxygen, oxygen+1, idef.iparams[type].settle.doh);
1207             sys->addConstraint(oxygen, oxygen+2, idef.iparams[type].settle.doh);
1208             sys->addConstraint(oxygen+1, oxygen+2, idef.iparams[type].settle.dhh);
1209         }
1210
1211         // Create an integrator for simulating the system.
1212         double friction = (ir->opts.tau_t[0] == 0.0 ? 0.0 : 1.0/ir->opts.tau_t[0]);
1213         Integrator* integ;
1214         if (ir->eI == eiBD)
1215         {
1216             integ = new BrownianIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1217             static_cast<BrownianIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
1218         }
1219         else if (EI_SD(ir->eI))
1220         {
1221             integ = new LangevinIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
1222             static_cast<LangevinIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
1223         }
1224         else 
1225         {
1226             integ = new VerletIntegrator(ir->delta_t);
1227             if ( ir->etc != etcNO)
1228             {
1229                 AndersenThermostat* thermostat = new AndersenThermostat(ir->opts.ref_t[0], friction); 
1230                 sys->addForce(thermostat);
1231             }           
1232         }
1233
1234                 // Add pressure coupling
1235         if (ir->epc != epcNO)
1236                 {
1237           // convert gromacs pressure tensor to a scalar
1238           double pressure = (ir->ref_p[0][0] + ir->ref_p[1][1] + ir->ref_p[2][2]) / 3.0;
1239           int frequency = int(ir->tau_p / ir->delta_t); // update frequency in time steps
1240           if (frequency < 1) frequency = 1;
1241           double temperature = ir->opts.ref_t[0]; // in kelvin
1242           sys->addForce(new MonteCarloBarostat(pressure, temperature, frequency));
1243                 }
1244
1245         integ->setConstraintTolerance(ir->shake_tol);
1246
1247         // Create a context and initialize it.
1248         Context* context = NULL;
1249
1250         /*      
1251         OpenMM could automatically select the "best" GPU, however we're not't 
1252         going to let it do that for now, as the current algorithm is very rudimentary
1253         and we anyway support only CUDA.        
1254         if (platformOptStr == NULL || platformOptStr == "")
1255         {
1256             context = new Context(*sys, *integ);
1257         }
1258         else
1259         */        
1260         {
1261             /* which platform should we use */
1262             for (int i = 0; i < (int)Platform::getNumPlatforms() && context == NULL; i++)
1263             {
1264                 if (isStringEqNCase(opt->getOptionValue("platform"), Platform::getPlatform(i).getName()))
1265                 {
1266                     Platform& platform = Platform::getPlatform(i);
1267                     // set standard properties
1268                     platform.setPropertyDefaultValue("CudaDevice", opt->getOptionValue("deviceid"));
1269                     // TODO add extra properties
1270                     context = new Context(*sys, *integ, platform);
1271                 }
1272             }
1273             if (context == NULL)
1274             {
1275                 gmx_fatal(FARGS, "The requested platform \"%s\" could not be found.", 
1276                         opt->getOptionValue("platform").c_str());
1277             }
1278         }
1279
1280         Platform& platform = context->getPlatform();
1281         fprintf(fplog, "Gromacs will use the OpenMM platform: %s\n", platform.getName().c_str());
1282
1283         const vector<string>& properties = platform.getPropertyNames();
1284         if (debug)
1285         {
1286             for (int i = 0; i < (int)properties.size(); i++)
1287             {
1288                 fprintf(debug, ">> %s: %s\n", properties[i].c_str(), 
1289                         platform.getPropertyValue(*context, properties[i]).c_str());
1290             }
1291         }
1292
1293         /* only for CUDA */
1294         if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1295         {
1296             int tmp;
1297             if (!from_string<int>(tmp, platform.getPropertyValue(*context, "CudaDevice"), std::dec))
1298             {
1299                 gmx_fatal(FARGS, "Internal error: couldn't determine the device selected by OpenMM");
1300
1301             }
1302
1303             /* For now this is just to double-check if OpenMM selected the GPU we wanted,
1304             but when we'll let OpenMM select the GPU automatically, it will query the deviceId.
1305             */            
1306             if (tmp != devId)
1307             {
1308                 gmx_fatal(FARGS, "Internal error: OpenMM is using device #%d"
1309                         "while initialized for device #%d", tmp, devId);
1310             }        
1311             
1312             /* check GPU compatibility */
1313             char gpuname[STRLEN];
1314             devId = atoi(opt->getOptionValue("deviceid").c_str());
1315             if (!is_gmx_openmm_supported_gpu(-1, gpuname))
1316             {
1317                 if (!gmx_strcasecmp(opt->getOptionValue("force-device").c_str(), "yes"))
1318                 {
1319                     sprintf(warn_buf, "Non-supported GPU selected (#%d, %s), forced continuing."
1320                             "Note, that the simulation can be slow or it migth even crash.", 
1321                             devId, gpuname);
1322                     fprintf(fplog, "%s\n", warn_buf);
1323                     gmx_warning(warn_buf);
1324                 }
1325                 else
1326                 {
1327                     gmx_fatal(FARGS, "The selected GPU (#%d, %s) is not supported by Gromacs! "
1328                               "Most probably you have a low-end GPU which would not perform well, " 
1329                               "or new hardware that has not been tested with the current release. "
1330                               "If you still want to try using the device, use the force-device=yes option.", 
1331                               devId, gpuname);
1332                 }
1333             }
1334             else
1335             {
1336                 fprintf(fplog, "Gromacs will run on the GPU #%d (%s).\n", devId, gpuname);
1337             }
1338         }
1339         
1340         /* only for CUDA */
1341         if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
1342         {
1343             /* pre-simulation memtest */
1344             runMemtest(fplog, -1, "Pre", opt);
1345         }
1346
1347         vector<Vec3> pos(numAtoms);
1348         vector<Vec3> vel(numAtoms);
1349         for (int i = 0; i < numAtoms; ++i)
1350         {
1351             pos[i] = Vec3(state->x[i][0], state->x[i][1], state->x[i][2]);
1352             vel[i] = Vec3(state->v[i][0], state->v[i][1], state->v[i][2]);
1353         }
1354         context->setPositions(pos);
1355         context->setVelocities(vel);
1356
1357         // Return a structure containing the system, integrator, and context.
1358         OpenMMData* data = new OpenMMData();
1359         data->system = sys;
1360         data->integrator = integ;
1361         data->context = context;
1362         data->removeCM = (ir->nstcomm > 0);
1363         data->platformOpt = opt;
1364         return data;
1365     }
1366     catch (std::exception& e)
1367     {
1368         gmx_fatal(FARGS, "OpenMM exception caught while initializating: %s", e.what());
1369     } 
1370     return NULL; /* just to avoid warnings */
1371 }
1372
1373 /*!
1374  * \brief Integrate one step.
1375  *
1376  * \param[in] data  OpenMMData object created by openmm_init().
1377  */
1378 void openmm_take_one_step(void* data)
1379 {
1380     // static int step = 0; printf("----> taking step #%d\n", step++);
1381     try
1382     {
1383         static_cast<OpenMMData*>(data)->integrator->step(1);
1384     }
1385     catch (std::exception& e)
1386     {
1387         gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1388     }
1389 }
1390
1391 /*!
1392  * \brief Integrate n steps.
1393  *
1394  * \param[in] data  OpenMMData object created by openmm_init().
1395  */
1396 void openmm_take_steps(void* data, int nstep)
1397 {
1398     try
1399     {
1400         static_cast<OpenMMData*>(data)->integrator->step(nstep);
1401     }
1402     catch (std::exception& e)
1403     {
1404         gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
1405     }
1406 }
1407
1408 /*!
1409  * \brief Clean up the data structures cretead for OpenMM.
1410  *
1411  * \param[in] log   Log file pointer.
1412  * \param[in] data  OpenMMData object created by openmm_init().
1413  */
1414 void openmm_cleanup(FILE* fplog, void* data)
1415 {
1416     OpenMMData* d = static_cast<OpenMMData*>(data);
1417     /* only for CUDA */
1418     if (isStringEqNCase(d->platformOpt->getOptionValue("platform"), "CUDA"))
1419     {
1420         /* post-simulation memtest */
1421         runMemtest(fplog, -1, "Post", d->platformOpt);
1422     }
1423     delete d->system;
1424     delete d->integrator;
1425     delete d->context;
1426     delete d->platformOpt;
1427     delete d;
1428 }
1429
1430 /*!
1431  * \brief Copy the current state information from OpenMM into the Gromacs data structures.
1432  * 
1433  * This function results in the requested proprties to be copied from the 
1434  * GPU to host. As this represents a bottleneck, the frequency of pulling data
1435  * should be minimized. 
1436  *
1437  * \param[in]   data        OpenMMData object created by openmm_init().
1438  * \param[out]  time        Simulation time for which the state was created.
1439  * \param[out]  state       State of the system: coordinates and velocities.
1440  * \param[out]  f           Forces.
1441  * \param[out]  enerd       Energies.
1442  * \param[in]   includePos  True if coordinates are requested.
1443  * \param[in]   includeVel  True if velocities are requested. 
1444  * \param[in]   includeForce True if forces are requested. 
1445  * \param[in]   includeEnergy True if energies are requested. 
1446  */
1447 void openmm_copy_state(void *data,
1448                        t_state *state, double *time,
1449                        rvec f[], gmx_enerdata_t *enerd,
1450                        gmx_bool includePos, gmx_bool includeVel, gmx_bool includeForce, gmx_bool includeEnergy)
1451 {
1452     int types = 0;
1453     if (includePos)
1454         types += State::Positions;
1455     if (includeVel)
1456         types += State::Velocities;
1457     if (includeForce)
1458         types += State::Forces;
1459     if (includeEnergy)
1460         types += State::Energy;
1461     if (types == 0)
1462         return;
1463     try
1464     {
1465         State currentState = static_cast<OpenMMData*>(data)->context->getState(types);
1466         int numAtoms =  static_cast<OpenMMData*>(data)->system->getNumParticles();
1467         if (includePos)
1468         {
1469             for (int i = 0; i < numAtoms; i++)
1470             {
1471                 Vec3 x = currentState.getPositions()[i];
1472                 state->x[i][0] = x[0];
1473                 state->x[i][1] = x[1];
1474                 state->x[i][2] = x[2];
1475             }
1476         }
1477         if (includeVel)
1478         {
1479             for (int i = 0; i < numAtoms; i++)
1480             {
1481                 Vec3 v = currentState.getVelocities()[i];
1482                 state->v[i][0] = v[0];
1483                 state->v[i][1] = v[1];
1484                 state->v[i][2] = v[2];
1485             }
1486         }
1487         if (includeForce)
1488         {
1489             for (int i = 0; i < numAtoms; i++)
1490             {
1491                 Vec3 force = currentState.getForces()[i];
1492                 f[i][0] = force[0];
1493                 f[i][1] = force[1];
1494                 f[i][2] = force[2];
1495             }
1496         }
1497         if (includeEnergy)
1498         {
1499             int numConstraints = static_cast<OpenMMData*>(data)->system->getNumConstraints();
1500             int dof = 3*numAtoms-numConstraints;
1501             if (static_cast<OpenMMData*>(data)->removeCM)
1502                 dof -= 3;
1503             enerd->term[F_EPOT] = currentState.getPotentialEnergy();
1504             enerd->term[F_EKIN] = currentState.getKineticEnergy();
1505             enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
1506             enerd->term[F_TEMP] = 2.0*enerd->term[F_EKIN]/dof/BOLTZ;
1507         }
1508         *time = currentState.getTime();
1509     }
1510     catch (std::exception& e)
1511     {
1512         gmx_fatal(FARGS, "OpenMM exception caught while retrieving state information: %s", e.what());
1513     }
1514 }