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