Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / mdlib / wall.c
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-2008, 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 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <math.h>
41 #include <string.h>
42 #include "maths.h"
43 #include "sysstuff.h"
44 #include "typedefs.h"
45 #include "macros.h"
46 #include "smalloc.h"
47 #include "force.h"
48 #include "filenm.h"
49 #include "nrnb.h"
50 #include "vec.h"
51
52 void make_wall_tables(FILE *fplog,const output_env_t oenv,
53                       const t_inputrec *ir,const char *tabfn,
54                       const gmx_groups_t *groups,
55                       t_forcerec *fr)
56 {
57   int  w,negp_pp,egp,i,j;
58   int  *nm_ind;
59   char buf[STRLEN];
60   t_forcetable *tab;
61
62   negp_pp = ir->opts.ngener - ir->nwall;
63   nm_ind  = groups->grps[egcENER].nm_ind;
64
65   if (fplog) {
66     fprintf(fplog,"Reading user tables for %d energy groups with %d walls\n",
67             negp_pp,ir->nwall);
68   }
69
70   snew(fr->wall_tab,ir->nwall);
71   for(w=0; w<ir->nwall; w++) {
72     snew(fr->wall_tab[w],negp_pp);
73     for(egp=0; egp<negp_pp; egp++) {
74       /* If the energy group pair is excluded, we don't need a table */
75       if (!(fr->egp_flags[egp*ir->opts.ngener+negp_pp+w] & EGP_EXCL)) {
76         tab = &fr->wall_tab[w][egp];
77         sprintf(buf,"%s",tabfn);
78         sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1,"_%s_%s.%s",
79                 *groups->grpname[nm_ind[egp]],
80                 *groups->grpname[nm_ind[negp_pp+w]],
81                 ftp2ext(efXVG));
82         *tab = make_tables(fplog,oenv,fr,FALSE,buf,0,GMX_MAKETABLES_FORCEUSER);
83         /* Since wall have no charge, we can compress the table */
84         for(i=0; i<=tab->n; i++)
85           for(j=0; j<8; j++)
86             tab->data[8*i+j] = tab->data[12*i+4+j];
87       }
88     }
89   }
90 }
91
92 static void wall_error(int a,rvec *x,real r)
93 {
94     gmx_fatal(FARGS,
95               "An atom is beyond the wall: coordinates %f %f %f, distance %f\n"
96               "You might want to use the mdp option wall_r_linpot",
97               x[a][XX],x[a][YY],x[a][ZZ],r);
98 }
99
100 real do_walls(t_inputrec *ir,t_forcerec *fr,matrix box,t_mdatoms *md,
101               rvec x[],rvec f[],real lambda,real Vlj[],t_nrnb *nrnb)
102 {
103     int  nwall,w,lam,i;
104     int  ntw[2],at,ntype,ngid,ggid,*egp_flags,*type;
105     real *nbfp,lamfac,fac_d[2],fac_r[2],Cd,Cr,Vtot,Fwall[2];
106     real wall_z[2],r,mr,r1,r2,r4,Vd,Vr,V=0,Fd,Fr,F=0,dvdlambda;
107     dvec xf_z;
108     int  n0,nnn;
109     real tabscale,*VFtab,rt,eps,eps2,Yt,Ft,Geps,Heps,Heps2,Fp,VV,FF;
110     unsigned short *gid=md->cENER;
111     t_forcetable *tab;
112
113     nwall     = ir->nwall;
114     ngid      = ir->opts.ngener;
115     ntype     = fr->ntype;
116     nbfp      = fr->nbfp;
117     egp_flags = fr->egp_flags;
118
119     for(w=0; w<nwall; w++)
120     {
121         ntw[w] = 2*ntype*ir->wall_atomtype[w];
122         switch (ir->wall_type)
123         {
124         case ewt93:
125             fac_d[w] = ir->wall_density[w]*M_PI/6;
126             fac_r[w] = ir->wall_density[w]*M_PI/45;
127             break;
128         case ewt104:
129             fac_d[w] = ir->wall_density[w]*M_PI/2;
130             fac_r[w] = ir->wall_density[w]*M_PI/5;
131             break;
132         default:
133             break;
134         }
135         Fwall[w] = 0;
136     }
137     wall_z[0] = 0;
138     wall_z[1] = box[ZZ][ZZ];
139
140     Vtot = 0;
141     dvdlambda = 0;
142     clear_dvec(xf_z);
143     for(lam=0; lam<(md->nPerturbed ? 2 : 1); lam++)
144     {
145         if (md->nPerturbed)
146         {
147             if (lam == 0)
148             {
149                 lamfac = 1 - lambda;
150                 type = md->typeA;
151             }
152             else
153             {
154                 lamfac = 0;
155                 type = md->typeB;
156             }
157         }
158         else
159         {
160             lamfac = 1;
161             type = md->typeA;
162         }
163         for(i=md->start; i<md->start+md->homenr; i++)
164         {
165             for(w=0; w<nwall; w++)
166             {
167                 /* The wall energy groups are always at the end of the list */
168                 ggid = gid[i]*ngid + ngid - nwall + w;
169                 at = type[i];
170                 /* nbfp now includes the 6.0/12.0 derivative prefactors */
171                 Cd = nbfp[ntw[w]+2*at]/6.0;
172                 Cr = nbfp[ntw[w]+2*at+1]/12.0;
173                 if (!((Cd==0 && Cr==0) || (egp_flags[ggid] & EGP_EXCL)))
174                 {
175                     if (w == 0)
176                     {
177                         r = x[i][ZZ];
178                     }
179                     else
180                     {
181                         r = wall_z[1] - x[i][ZZ];
182                     }
183                     if (r < ir->wall_r_linpot)
184                     {
185                         mr = ir->wall_r_linpot - r;
186                         r  = ir->wall_r_linpot;
187                     }
188                     else
189                     {
190                         mr = 0;
191                     }
192                     switch (ir->wall_type)
193                     {
194                     case ewtTABLE:
195                         if (r < 0)
196                         {
197                             wall_error(i,x,r);
198                         }
199                         tab = &(fr->wall_tab[w][gid[i]]);
200                         tabscale = tab->scale;
201                         VFtab    = tab->data;
202                         
203                         rt    = r*tabscale;
204                         n0    = rt;
205                         if (n0 >= tab->n)
206                         {
207                             /* Beyond the table range, set V and F to zero */
208                             V     = 0;
209                             F     = 0;
210                         }
211                         else
212                         {
213                             eps   = rt - n0;
214                             eps2  = eps*eps;
215                             /* Dispersion */
216                             nnn   = 8*n0;
217                             Yt    = VFtab[nnn];
218                             Ft    = VFtab[nnn+1];
219                             Geps  = VFtab[nnn+2]*eps;
220                             Heps2 = VFtab[nnn+3]*eps2;
221                             Fp    = Ft + Geps + Heps2;
222                             VV    = Yt + Fp*eps;
223                             FF    = Fp + Geps + 2.0*Heps2;
224                             Vd    = Cd*VV;
225                             Fd    = Cd*FF;
226                             /* Repulsion */
227                             nnn   = nnn + 4;
228                             Yt    = VFtab[nnn];
229                             Ft    = VFtab[nnn+1];
230                             Geps  = VFtab[nnn+2]*eps;
231                             Heps2 = VFtab[nnn+3]*eps2;
232                             Fp    = Ft + Geps + Heps2;
233                             VV    = Yt + Fp*eps;
234                             FF    = Fp + Geps + 2.0*Heps2;
235                             Vr    = Cr*VV;
236                             Fr    = Cr*FF;
237                             V     = Vd + Vr;
238                             F     = -lamfac*(Fd + Fr)*tabscale;
239                         }
240                         break;
241                     case ewt93:
242                         if (r <= 0)
243                         {
244                             wall_error(i,x,r);
245                         }
246                         r1 = 1/r;
247                         r2 = r1*r1;
248                         r4 = r2*r2;
249                         Vd = fac_d[w]*Cd*r2*r1;
250                         Vr = fac_r[w]*Cr*r4*r4*r1;
251                         V  = Vr - Vd;
252                         F  = lamfac*(9*Vr - 3*Vd)*r1;
253                         break;
254                     case ewt104:
255                         if (r <= 0)
256                         {
257                             wall_error(i,x,r);
258                         }
259                         r1 = 1/r;
260                         r2 = r1*r1;
261                         r4 = r2*r2;
262                         Vd = fac_d[w]*Cd*r4;
263                         Vr = fac_r[w]*Cr*r4*r4*r2;
264                         V  = Vr - Vd;
265                         F  = lamfac*(10*Vr - 4*Vd)*r1;
266                         break;
267                     case ewt126:
268                         if (r <= 0)
269                         {
270                             wall_error(i,x,r);
271                         }
272                         r1 = 1/r;
273                         r2 = r1*r1;
274                         r4 = r2*r2;
275                         Vd = Cd*r4*r2;
276                         Vr = Cr*r4*r4*r4;
277                         V  = Vr - Vd;
278                         F  = lamfac*(12*Vr - 6*Vd)*r1;
279                         break;
280                     default:
281                         break;
282                     }
283                     if (mr > 0)
284                     {
285                         V += mr*F;
286                     }
287                     if (w == 1)
288                     {
289                         F = -F;
290                     }
291                     Vlj[ggid] += lamfac*V;
292                     Vtot      += V;
293                     f[i][ZZ]  += F;
294                     /* Because of the single sum virial calculation we need
295                      * to add  the full virial contribution of the walls.
296                      * Since the force only has a z-component, there is only
297                      * a contribution to the z component of the virial tensor.
298                      * We could also determine the virial contribution directly,
299                      * which would be cheaper here, but that would require extra
300                      * communication for f_novirsum for with virtual sites
301                      * in parallel.
302                      */
303                     xf_z[XX]  -= x[i][XX]*F;
304                     xf_z[YY]  -= x[i][YY]*F;
305                     xf_z[ZZ]  -= wall_z[w]*F;
306                 }
307             }
308         }
309         if (md->nPerturbed)
310         {
311             dvdlambda += (lam==0 ? -1 : 1)*Vtot;
312         }
313         
314         inc_nrnb(nrnb,eNR_WALLS,md->homenr);
315     }
316
317     for(i=0; i<DIM; i++)
318     {
319         fr->vir_wall_z[i] = -0.5*xf_z[i];
320     }
321
322     return dvdlambda;
323 }