Fix part of old-style casting
[alexxy/gromacs.git] / src / gromacs / mdlib / rf_util.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) 2013,2014,2015,2017,2018, 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 "rf_util.h"
40
41 #include <cmath>
42
43 #include "gromacs/math/functions.h"
44 #include "gromacs/math/units.h"
45 #include "gromacs/math/vec.h"
46 #include "gromacs/mdtypes/forcerec.h"
47 #include "gromacs/mdtypes/inputrec.h"
48 #include "gromacs/mdtypes/md_enums.h"
49 #include "gromacs/mdtypes/mdatom.h"
50 #include "gromacs/pbcutil/ishift.h"
51 #include "gromacs/pbcutil/mshift.h"
52 #include "gromacs/pbcutil/pbc.h"
53 #include "gromacs/topology/topology.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/pleasecite.h"
56
57 real RF_excl_correction(const t_forcerec *fr,
58                         const t_graph    *g,
59                         const t_mdatoms  *mdatoms,
60                         const t_blocka   *excl,
61                         bool              usingDomainDecomposition,
62                         rvec              x[],
63                         rvec              f[],
64                         rvec             *fshift,
65                         const t_pbc      *pbc,
66                         real              lambda,
67                         real             *dvdlambda)
68 {
69     /* Calculate the reaction-field energy correction for this node:
70      * epsfac q_i q_j (k_rf r_ij^2 - c_rf)
71      * and force correction for all excluded pairs, including self pairs.
72      */
73     int         i, j, j1, j2, k, ki;
74     double      q2sumA, q2sumB, ener;
75     const real *chargeA, *chargeB;
76     real        ek, ec, L1, qiA, qiB, qqA, qqB, qqL, v;
77     rvec        dx, df;
78     int        *AA;
79     ivec        dt;
80     int         start = 0;
81     int         end   = mdatoms->homenr;
82     int         niat;
83     gmx_bool    bMolPBC = fr->bMolPBC;
84
85     if (fr->n_tpi)
86     {
87         /* For test particle insertion we only correct for the test molecule */
88         start = mdatoms->nr - fr->n_tpi;
89     }
90
91     ek      = fr->ic->epsfac*fr->ic->k_rf;
92     ec      = fr->ic->epsfac*fr->ic->c_rf;
93     chargeA = mdatoms->chargeA;
94     chargeB = mdatoms->chargeB;
95     AA      = excl->a;
96     ki      = CENTRAL;
97
98     if (usingDomainDecomposition)
99     {
100         niat = excl->nr;
101     }
102     else
103     {
104         niat = end;
105     }
106
107     q2sumA = 0;
108     q2sumB = 0;
109     ener   = 0;
110     if (mdatoms->nChargePerturbed == 0)
111     {
112         for (i = start; i < niat; i++)
113         {
114             qiA = chargeA[i];
115             if (i < end)
116             {
117                 q2sumA += qiA*qiA;
118             }
119             /* Do the exclusions */
120             j1  = excl->index[i];
121             j2  = excl->index[i+1];
122             for (j = j1; j < j2; j++)
123             {
124                 k = AA[j];
125                 if (k > i)
126                 {
127                     qqA = qiA*chargeA[k];
128                     if (qqA != 0)
129                     {
130                         if (g)
131                         {
132                             rvec_sub(x[i], x[k], dx);
133                             ivec_sub(SHIFT_IVEC(g, i), SHIFT_IVEC(g, k), dt);
134                             ki = IVEC2IS(dt);
135                         }
136                         else if (bMolPBC)
137                         {
138                             ki = pbc_dx_aiuc(pbc, x[i], x[k], dx);
139                         }
140                         else
141                         {
142                             rvec_sub(x[i], x[k], dx);
143                         }
144                         ener += qqA*(ek*norm2(dx) - ec);
145                         svmul(-2*qqA*ek, dx, df);
146                         rvec_inc(f[i], df);
147                         rvec_dec(f[k], df);
148                         rvec_inc(fshift[ki], df);
149                         rvec_dec(fshift[CENTRAL], df);
150                     }
151                 }
152             }
153         }
154         ener += -0.5*ec*q2sumA;
155     }
156     else
157     {
158         L1 = 1.0 - lambda;
159         for (i = start; i < niat; i++)
160         {
161             qiA = chargeA[i];
162             qiB = chargeB[i];
163             if (i < end)
164             {
165                 q2sumA += qiA*qiA;
166                 q2sumB += qiB*qiB;
167             }
168             /* Do the exclusions */
169             j1  = excl->index[i];
170             j2  = excl->index[i+1];
171             for (j = j1; j < j2; j++)
172             {
173                 k = AA[j];
174                 if (k > i)
175                 {
176                     qqA = qiA*chargeA[k];
177                     qqB = qiB*chargeB[k];
178                     if (qqA != 0 || qqB != 0)
179                     {
180                         qqL = L1*qqA + lambda*qqB;
181                         if (g)
182                         {
183                             rvec_sub(x[i], x[k], dx);
184                             ivec_sub(SHIFT_IVEC(g, i), SHIFT_IVEC(g, k), dt);
185                             ki = IVEC2IS(dt);
186                         }
187                         else if (bMolPBC)
188                         {
189                             ki = pbc_dx_aiuc(pbc, x[i], x[k], dx);
190                         }
191                         else
192                         {
193                             rvec_sub(x[i], x[k], dx);
194                         }
195                         v     = ek*norm2(dx) - ec;
196                         ener += qqL*v;
197                         svmul(-2*qqL*ek, dx, df);
198                         rvec_inc(f[i], df);
199                         rvec_dec(f[k], df);
200                         rvec_inc(fshift[ki], df);
201                         rvec_dec(fshift[CENTRAL], df);
202                         *dvdlambda += (qqB - qqA)*v;
203                     }
204                 }
205             }
206         }
207         ener       += -0.5*ec*(L1*q2sumA + lambda*q2sumB);
208         *dvdlambda += -0.5*ec*(q2sumB - q2sumA);
209     }
210
211     if (debug)
212     {
213         fprintf(debug, "RF exclusion energy: %g\n", ener);
214     }
215
216     return ener;
217 }
218
219 void calc_rffac(FILE *fplog, int eel, real eps_r, real eps_rf, real Rc, real Temp,
220                 real zsq, matrix box,
221                 real *krf, real *crf)
222 {
223     /* Compute constants for Generalized reaction field */
224     real   kappa, k1, k2, I, rmin;
225     real   vol = 0;
226
227     if (EEL_RF(eel))
228     {
229         if (eel == eelGRF)
230         {
231             /* Consistency check */
232             if (Temp <= 0.0)
233             {
234                 gmx_fatal(FARGS, "Temperature is %f while using"
235                           " Generalized Reaction Field\n", Temp);
236             }
237             /* Ionic strength (only needed for eelGRF */
238             vol     = det(box);
239             I       = 0.5*zsq/vol;
240             kappa   = std::sqrt(2*I/(EPSILON0*eps_rf*BOLTZ*Temp));
241         }
242         else
243         {
244             I      = 0;
245             kappa  = 0;
246         }
247
248         /* eps == 0 signals infinite dielectric */
249         if (eps_rf == 0)
250         {
251             *krf = 1/(2*Rc*Rc*Rc);
252         }
253         else
254         {
255             k1   = 1 + kappa*Rc;
256             k2   = eps_rf*gmx::square(static_cast<real>(kappa*Rc));
257
258             *krf = ((eps_rf - eps_r)*k1 + 0.5*k2)/((2*eps_rf + eps_r)*k1 + k2)/(Rc*Rc*Rc);
259         }
260         *crf   = 1/Rc + *krf*Rc*Rc;
261         // Make sure we don't lose resolution in pow() by casting real arg to double
262         rmin   = gmx::invcbrt(static_cast<double>(*krf*2.0));
263
264         if (fplog)
265         {
266             if (eel == eelGRF)
267             {
268                 please_cite(fplog, "Tironi95a");
269                 fprintf(fplog, "%s:\n"
270                         "epsRF = %10g, I   = %10g, volume = %10g, kappa  = %10g\n"
271                         "rc    = %10g, krf = %10g, crf    = %10g, epsfac = %10g\n",
272                         eel_names[eel], eps_rf, I, vol, kappa, Rc, *krf, *crf,
273                         ONE_4PI_EPS0/eps_r);
274             }
275             else
276             {
277                 fprintf(fplog, "%s:\n"
278                         "epsRF = %g, rc = %g, krf = %g, crf = %g, epsfac = %g\n",
279                         eel_names[eel], eps_rf, Rc, *krf, *crf, ONE_4PI_EPS0/eps_r);
280             }
281             fprintf(fplog,
282                     "The electrostatics potential has its minimum at r = %g\n",
283                     rmin);
284         }
285     }
286 }
287
288 void init_generalized_rf(FILE *fplog,
289                          const gmx_mtop_t *mtop, const t_inputrec *ir,
290                          t_forcerec *fr)
291 {
292     int                  i, j;
293     real                 q, zsq, nrdf, T;
294     const gmx_moltype_t *molt;
295     const t_block       *cgs;
296
297     if (ir->efep != efepNO && fplog)
298     {
299         fprintf(fplog, "\nWARNING: the generalized reaction field constants are determined from topology A only\n\n");
300     }
301     zsq = 0.0;
302     for (const gmx_molblock_t &molb : mtop->molblock)
303     {
304         molt = &mtop->moltype[molb.type];
305         cgs  = &molt->cgs;
306         for (i = 0; (i < cgs->nr); i++)
307         {
308             q = 0;
309             for (j = cgs->index[i]; (j < cgs->index[i+1]); j++)
310             {
311                 q += molt->atoms.atom[j].q;
312             }
313             zsq += molb.nmol*q*q;
314         }
315         fr->zsquare = zsq;
316     }
317
318     T    = 0.0;
319     nrdf = 0.0;
320     for (i = 0; (i < ir->opts.ngtc); i++)
321     {
322         nrdf += ir->opts.nrdf[i];
323         T    += (ir->opts.nrdf[i] * ir->opts.ref_t[i]);
324     }
325     if (nrdf == 0)
326     {
327         gmx_fatal(FARGS, "No degrees of freedom!");
328     }
329     fr->temp   = T/nrdf;
330 }