bbcba4bfaee2e1e580f9798c272f6a1a78eaaa6f
[alexxy/gromacs.git] / src / gromacs / mdlib / mdatoms.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "mdatoms.h"
40
41 #include <math.h>
42
43 #include "gromacs/math/functions.h"
44 #include "gromacs/mdlib/gmx_omp_nthreads.h"
45 #include "gromacs/mdlib/qmmm.h"
46 #include "gromacs/mdtypes/inputrec.h"
47 #include "gromacs/mdtypes/md_enums.h"
48 #include "gromacs/topology/mtop_lookup.h"
49 #include "gromacs/topology/mtop_util.h"
50 #include "gromacs/topology/topology.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/smalloc.h"
53
54 #define ALMOST_ZERO 1e-30
55
56 t_mdatoms *init_mdatoms(FILE *fp, const gmx_mtop_t *mtop, gmx_bool bFreeEnergy)
57 {
58     int                     a;
59     double                  tmA, tmB;
60     const t_atom           *atom;
61     t_mdatoms              *md;
62     gmx_mtop_atomloop_all_t aloop;
63
64     snew(md, 1);
65
66     md->nenergrp = mtop->groups.grps[egcENER].nr;
67     md->bVCMgrps = FALSE;
68     tmA          = 0.0;
69     tmB          = 0.0;
70
71     aloop = gmx_mtop_atomloop_all_init(mtop);
72     while (gmx_mtop_atomloop_all_next(aloop, &a, &atom))
73     {
74         if (ggrpnr(&mtop->groups, egcVCM, a) > 0)
75         {
76             md->bVCMgrps = TRUE;
77         }
78
79         if (bFreeEnergy && PERTURBED(*atom))
80         {
81             md->nPerturbed++;
82             if (atom->mB != atom->m)
83             {
84                 md->nMassPerturbed++;
85             }
86             if (atom->qB != atom->q)
87             {
88                 md->nChargePerturbed++;
89             }
90             if (atom->typeB != atom->type)
91             {
92                 md->nTypePerturbed++;
93             }
94         }
95
96         tmA += atom->m;
97         tmB += atom->mB;
98     }
99
100     md->tmassA = tmA;
101     md->tmassB = tmB;
102
103     if (bFreeEnergy && fp)
104     {
105         fprintf(fp,
106                 "There are %d atoms and %d charges for free energy perturbation\n",
107                 md->nPerturbed, md->nChargePerturbed);
108     }
109
110     md->bOrires = gmx_mtop_ftype_count(mtop, F_ORIRES);
111
112     return md;
113 }
114
115 void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
116               int nindex, const int *index,
117               int homenr,
118               t_mdatoms *md)
119 {
120     gmx_bool              bLJPME;
121     const t_grpopts      *opts;
122     const gmx_groups_t   *groups;
123     int                   nthreads gmx_unused;
124
125     bLJPME = EVDW_PME(ir->vdwtype);
126
127     opts = &ir->opts;
128
129     groups = &mtop->groups;
130
131     /* nindex>=0 indicates DD where we use an index */
132     if (nindex >= 0)
133     {
134         md->nr = nindex;
135     }
136     else
137     {
138         md->nr = mtop->natoms;
139     }
140
141     if (md->nr > md->nalloc)
142     {
143         md->nalloc = over_alloc_dd(md->nr);
144
145         if (md->nMassPerturbed)
146         {
147             srenew(md->massA, md->nalloc);
148             srenew(md->massB, md->nalloc);
149         }
150         srenew(md->massT, md->nalloc);
151         srenew(md->invmass, md->nalloc);
152         srenew(md->invMassPerDim, md->nalloc);
153         srenew(md->chargeA, md->nalloc);
154         srenew(md->typeA, md->nalloc);
155         if (md->nPerturbed)
156         {
157             srenew(md->chargeB, md->nalloc);
158             srenew(md->typeB, md->nalloc);
159         }
160         if (bLJPME)
161         {
162             srenew(md->sqrt_c6A, md->nalloc);
163             srenew(md->sigmaA, md->nalloc);
164             srenew(md->sigma3A, md->nalloc);
165             if (md->nPerturbed)
166             {
167                 srenew(md->sqrt_c6B, md->nalloc);
168                 srenew(md->sigmaB, md->nalloc);
169                 srenew(md->sigma3B, md->nalloc);
170             }
171         }
172         srenew(md->ptype, md->nalloc);
173         if (opts->ngtc > 1)
174         {
175             srenew(md->cTC, md->nalloc);
176             /* We always copy cTC with domain decomposition */
177         }
178         srenew(md->cENER, md->nalloc);
179         if (opts->ngacc > 1)
180         {
181             srenew(md->cACC, md->nalloc);
182         }
183         if (opts->nFreeze &&
184             (opts->ngfrz > 1 ||
185              opts->nFreeze[0][XX] || opts->nFreeze[0][YY] || opts->nFreeze[0][ZZ]))
186         {
187             srenew(md->cFREEZE, md->nalloc);
188         }
189         if (md->bVCMgrps)
190         {
191             srenew(md->cVCM, md->nalloc);
192         }
193         if (md->bOrires)
194         {
195             srenew(md->cORF, md->nalloc);
196         }
197         if (md->nPerturbed)
198         {
199             srenew(md->bPerturbed, md->nalloc);
200         }
201
202         /* Note that these user t_mdatoms array pointers are NULL
203          * when there is only one group present.
204          * Therefore, when adding code, the user should use something like:
205          * gprnrU1 = (md->cU1==NULL ? 0 : md->cU1[localatindex])
206          */
207         if (mtop->groups.grpnr[egcUser1] != NULL)
208         {
209             srenew(md->cU1, md->nalloc);
210         }
211         if (mtop->groups.grpnr[egcUser2] != NULL)
212         {
213             srenew(md->cU2, md->nalloc);
214         }
215
216         if (ir->bQMMM)
217         {
218             srenew(md->bQM, md->nalloc);
219         }
220     }
221
222     int molb = 0;
223
224     // cppcheck-suppress unreadVariable
225     nthreads = gmx_omp_nthreads_get(emntDefault);
226 #pragma omp parallel for num_threads(nthreads) schedule(static) firstprivate(molb)
227     for (int i = 0; i < md->nr; i++)
228     {
229         try
230         {
231             int      g, ag;
232             real     mA, mB, fac;
233             real     c6, c12;
234
235             if (index == NULL)
236             {
237                 ag = i;
238             }
239             else
240             {
241                 ag = index[i];
242             }
243             const t_atom &atom = mtopGetAtomParameters(mtop, ag, &molb);
244
245             if (md->cFREEZE)
246             {
247                 md->cFREEZE[i] = ggrpnr(groups, egcFREEZE, ag);
248             }
249             if (EI_ENERGY_MINIMIZATION(ir->eI))
250             {
251                 /* Displacement is proportional to F, masses used for constraints */
252                 mA = 1.0;
253                 mB = 1.0;
254             }
255             else if (ir->eI == eiBD)
256             {
257                 /* With BD the physical masses are irrelevant.
258                  * To keep the code simple we use most of the normal MD code path
259                  * for BD. Thus for constraining the masses should be proportional
260                  * to the friction coefficient. We set the absolute value such that
261                  * m/2<(dx/dt)^2> = m/2*2kT/fric*dt = kT/2 => m=fric*dt/2
262                  * Then if we set the (meaningless) velocity to v=dx/dt, we get the
263                  * correct kinetic energy and temperature using the usual code path.
264                  * Thus with BD v*dt will give the displacement and the reported
265                  * temperature can signal bad integration (too large time step).
266                  */
267                 if (ir->bd_fric > 0)
268                 {
269                     mA = 0.5*ir->bd_fric*ir->delta_t;
270                     mB = 0.5*ir->bd_fric*ir->delta_t;
271                 }
272                 else
273                 {
274                     /* The friction coefficient is mass/tau_t */
275                     fac = ir->delta_t/opts->tau_t[md->cTC ? groups->grpnr[egcTC][ag] : 0];
276                     mA  = 0.5*atom.m*fac;
277                     mB  = 0.5*atom.mB*fac;
278                 }
279             }
280             else
281             {
282                 mA = atom.m;
283                 mB = atom.mB;
284             }
285             if (md->nMassPerturbed)
286             {
287                 md->massA[i]  = mA;
288                 md->massB[i]  = mB;
289             }
290             md->massT[i]    = mA;
291
292             if (mA == 0.0)
293             {
294                 md->invmass[i]           = 0;
295                 md->invMassPerDim[i][XX] = 0;
296                 md->invMassPerDim[i][YY] = 0;
297                 md->invMassPerDim[i][ZZ] = 0;
298             }
299             else if (md->cFREEZE)
300             {
301                 g = md->cFREEZE[i];
302                 if (opts->nFreeze[g][XX] && opts->nFreeze[g][YY] && opts->nFreeze[g][ZZ])
303                 {
304                     /* Set the mass of completely frozen particles to ALMOST_ZERO
305                      * iso 0 to avoid div by zero in lincs or shake.
306                      */
307                     md->invmass[i]  = ALMOST_ZERO;
308                 }
309                 else
310                 {
311                     /* Note: Partially frozen particles use the normal invmass.
312                      * If such particles are constrained, the frozen dimensions
313                      * should not be updated with the constrained coordinates.
314                      */
315                     md->invmass[i]  = 1.0/mA;
316                 }
317                 for (int d = 0; d < DIM; d++)
318                 {
319                     md->invMassPerDim[i][d] = (opts->nFreeze[g][d] ? 0 : 1.0/mA);
320                 }
321             }
322             else
323             {
324                 md->invmass[i]  = 1.0/mA;
325                 for (int d = 0; d < DIM; d++)
326                 {
327                     md->invMassPerDim[i][d] = 1.0/mA;
328                 }
329             }
330
331             md->chargeA[i]      = atom.q;
332             md->typeA[i]        = atom.type;
333             if (bLJPME)
334             {
335                 c6                = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c6;
336                 c12               = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c12;
337                 md->sqrt_c6A[i]   = sqrt(c6);
338                 if (c6 == 0.0 || c12 == 0)
339                 {
340                     md->sigmaA[i] = 1.0;
341                 }
342                 else
343                 {
344                     md->sigmaA[i] = gmx::sixthroot(c12/c6);
345                 }
346                 md->sigma3A[i]    = 1/(md->sigmaA[i]*md->sigmaA[i]*md->sigmaA[i]);
347             }
348             if (md->nPerturbed)
349             {
350                 md->bPerturbed[i] = PERTURBED(atom);
351                 md->chargeB[i]    = atom.qB;
352                 md->typeB[i]      = atom.typeB;
353                 if (bLJPME)
354                 {
355                     c6                = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c6;
356                     c12               = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c12;
357                     md->sqrt_c6B[i]   = sqrt(c6);
358                     if (c6 == 0.0 || c12 == 0)
359                     {
360                         md->sigmaB[i] = 1.0;
361                     }
362                     else
363                     {
364                         md->sigmaB[i] = gmx::sixthroot(c12/c6);
365                     }
366                     md->sigma3B[i]    = 1/(md->sigmaB[i]*md->sigmaB[i]*md->sigmaB[i]);
367                 }
368             }
369             md->ptype[i]    = atom.ptype;
370             if (md->cTC)
371             {
372                 md->cTC[i]    = groups->grpnr[egcTC][ag];
373             }
374             md->cENER[i]    =
375                 (groups->grpnr[egcENER] ? groups->grpnr[egcENER][ag] : 0);
376             if (md->cACC)
377             {
378                 md->cACC[i]   = groups->grpnr[egcACC][ag];
379             }
380             if (md->cVCM)
381             {
382                 md->cVCM[i]       = groups->grpnr[egcVCM][ag];
383             }
384             if (md->cORF)
385             {
386                 md->cORF[i]       = groups->grpnr[egcORFIT][ag];
387             }
388
389             if (md->cU1)
390             {
391                 md->cU1[i]        = groups->grpnr[egcUser1][ag];
392             }
393             if (md->cU2)
394             {
395                 md->cU2[i]        = groups->grpnr[egcUser2][ag];
396             }
397
398             if (ir->bQMMM)
399             {
400                 if (groups->grpnr[egcQMMM] == 0 ||
401                     groups->grpnr[egcQMMM][ag] < groups->grps[egcQMMM].nr-1)
402                 {
403                     md->bQM[i]      = TRUE;
404                 }
405                 else
406                 {
407                     md->bQM[i]      = FALSE;
408                 }
409             }
410         }
411         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
412     }
413
414     md->homenr = homenr;
415     /* We set mass, invmass, invMassPerDim and tmass for lambda=0.
416      * For free-energy runs, these should be updated using update_mdatoms().
417      */
418     md->tmass  = md->tmassA;
419     md->lambda = 0;
420 }
421
422 void update_mdatoms(t_mdatoms *md, real lambda)
423 {
424     if (md->nMassPerturbed && lambda != md->lambda)
425     {
426         real L1 = 1 - lambda;
427
428         /* Update masses of perturbed atoms for the change in lambda */
429         // cppcheck-suppress unreadVariable
430         int gmx_unused nthreads = gmx_omp_nthreads_get(emntDefault);
431 #pragma omp parallel for num_threads(nthreads) schedule(static)
432         for (int i = 0; i < md->nr; i++)
433         {
434             if (md->bPerturbed[i])
435             {
436                 md->massT[i] = L1*md->massA[i] + lambda*md->massB[i];
437                 /* Atoms with invmass 0 or ALMOST_ZERO are massless or frozen
438                  * and their invmass does not depend on lambda.
439                  */
440                 if (md->invmass[i] > 1.1*ALMOST_ZERO)
441                 {
442                     md->invmass[i] = 1.0/md->massT[i];
443                     for (int d = 0; d < DIM; d++)
444                     {
445                         if (md->invMassPerDim[i][d] > 1.1*ALMOST_ZERO)
446                         {
447                             md->invMassPerDim[i][d] = md->invmass[i];
448                         }
449                     }
450                 }
451             }
452         }
453
454         /* Update the system mass for the change in lambda */
455         md->tmass  = L1*md->tmassA + lambda*md->tmassB;
456     }
457
458     md->lambda = lambda;
459 }