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