Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / mdlib / wall.c
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-2008, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include <math.h>
44 #include <string.h>
45 #include "maths.h"
46 #include "sysstuff.h"
47 #include "typedefs.h"
48 #include "macros.h"
49 #include "smalloc.h"
50 #include "force.h"
51 #include "filenm.h"
52 #include "nrnb.h"
53 #include "vec.h"
54
55 void make_wall_tables(FILE *fplog,const output_env_t oenv,
56                       const t_inputrec *ir,const char *tabfn,
57                       const gmx_groups_t *groups,
58                       t_forcerec *fr)
59 {
60   int  w,negp_pp,egp,i,j;
61   int  *nm_ind;
62   char buf[STRLEN];
63   t_forcetable *tab;
64
65   negp_pp = ir->opts.ngener - ir->nwall;
66   nm_ind  = groups->grps[egcENER].nm_ind;
67
68   if (fplog) {
69     fprintf(fplog,"Reading user tables for %d energy groups with %d walls\n",
70             negp_pp,ir->nwall);
71   }
72
73   snew(fr->wall_tab,ir->nwall);
74   for(w=0; w<ir->nwall; w++) {
75     snew(fr->wall_tab[w],negp_pp);
76     for(egp=0; egp<negp_pp; egp++) {
77       /* If the energy group pair is excluded, we don't need a table */
78       if (!(fr->egp_flags[egp*ir->opts.ngener+negp_pp+w] & EGP_EXCL)) {
79         tab = &fr->wall_tab[w][egp];
80         sprintf(buf,"%s",tabfn);
81         sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1,"_%s_%s.%s",
82                 *groups->grpname[nm_ind[egp]],
83                 *groups->grpname[nm_ind[negp_pp+w]],
84                 ftp2ext(efXVG));
85         *tab = make_tables(fplog,oenv,fr,FALSE,buf,0,GMX_MAKETABLES_FORCEUSER);
86         /* Since wall have no charge, we can compress the table */
87         for(i=0; i<=tab->n; i++)
88           for(j=0; j<8; j++)
89             tab->data[8*i+j] = tab->data[12*i+4+j];
90       }
91     }
92   }
93 }
94
95 static void wall_error(int a,rvec *x,real r)
96 {
97     gmx_fatal(FARGS,
98               "An atom is beyond the wall: coordinates %f %f %f, distance %f\n"
99               "You might want to use the mdp option wall_r_linpot",
100               x[a][XX],x[a][YY],x[a][ZZ],r);
101 }
102
103 real do_walls(t_inputrec *ir,t_forcerec *fr,matrix box,t_mdatoms *md,
104               rvec x[],rvec f[],real lambda,real Vlj[],t_nrnb *nrnb)
105 {
106     int  nwall,w,lam,i;
107     int  ntw[2],at,ntype,ngid,ggid,*egp_flags,*type;
108     real *nbfp,lamfac,fac_d[2],fac_r[2],Cd,Cr,Vtot,Fwall[2];
109     real wall_z[2],r,mr,r1,r2,r4,Vd,Vr,V=0,Fd,Fr,F=0,dvdlambda;
110     dvec xf_z;
111     int  n0,nnn;
112     real tabscale,*VFtab,rt,eps,eps2,Yt,Ft,Geps,Heps,Heps2,Fp,VV,FF;
113     unsigned short *gid=md->cENER;
114     t_forcetable *tab;
115
116     nwall     = ir->nwall;
117     ngid      = ir->opts.ngener;
118     ntype     = fr->ntype;
119     nbfp      = fr->nbfp;
120     egp_flags = fr->egp_flags;
121
122     for(w=0; w<nwall; w++)
123     {
124         ntw[w] = 2*ntype*ir->wall_atomtype[w];
125         switch (ir->wall_type)
126         {
127         case ewt93:
128             fac_d[w] = ir->wall_density[w]*M_PI/6;
129             fac_r[w] = ir->wall_density[w]*M_PI/45;
130             break;
131         case ewt104:
132             fac_d[w] = ir->wall_density[w]*M_PI/2;
133             fac_r[w] = ir->wall_density[w]*M_PI/5;
134             break;
135         default:
136             break;
137         }
138         Fwall[w] = 0;
139     }
140     wall_z[0] = 0;
141     wall_z[1] = box[ZZ][ZZ];
142
143     Vtot = 0;
144     dvdlambda = 0;
145     clear_dvec(xf_z);
146     for(lam=0; lam<(md->nPerturbed ? 2 : 1); lam++)
147     {
148         if (md->nPerturbed)
149         {
150             if (lam == 0)
151             {
152                 lamfac = 1 - lambda;
153                 type = md->typeA;
154             }
155             else
156             {
157                 lamfac = 0;
158                 type = md->typeB;
159             }
160         }
161         else
162         {
163             lamfac = 1;
164             type = md->typeA;
165         }
166         for(i=md->start; i<md->start+md->homenr; i++)
167         {
168             for(w=0; w<nwall; w++)
169             {
170                 /* The wall energy groups are always at the end of the list */
171                 ggid = gid[i]*ngid + ngid - nwall + w;
172                 at = type[i];
173                 /* nbfp now includes the 6.0/12.0 derivative prefactors */
174                 Cd = nbfp[ntw[w]+2*at]/6.0;
175                 Cr = nbfp[ntw[w]+2*at+1]/12.0;
176                 if (!((Cd==0 && Cr==0) || (egp_flags[ggid] & EGP_EXCL)))
177                 {
178                     if (w == 0)
179                     {
180                         r = x[i][ZZ];
181                     }
182                     else
183                     {
184                         r = wall_z[1] - x[i][ZZ];
185                     }
186                     if (r < ir->wall_r_linpot)
187                     {
188                         mr = ir->wall_r_linpot - r;
189                         r  = ir->wall_r_linpot;
190                     }
191                     else
192                     {
193                         mr = 0;
194                     }
195                     switch (ir->wall_type)
196                     {
197                     case ewtTABLE:
198                         if (r < 0)
199                         {
200                             wall_error(i,x,r);
201                         }
202                         tab = &(fr->wall_tab[w][gid[i]]);
203                         tabscale = tab->scale;
204                         VFtab    = tab->data;
205                         
206                         rt    = r*tabscale;
207                         n0    = rt;
208                         if (n0 >= tab->n)
209                         {
210                             /* Beyond the table range, set V and F to zero */
211                             V     = 0;
212                             F     = 0;
213                         }
214                         else
215                         {
216                             eps   = rt - n0;
217                             eps2  = eps*eps;
218                             /* Dispersion */
219                             nnn   = 8*n0;
220                             Yt    = VFtab[nnn];
221                             Ft    = VFtab[nnn+1];
222                             Geps  = VFtab[nnn+2]*eps;
223                             Heps2 = VFtab[nnn+3]*eps2;
224                             Fp    = Ft + Geps + Heps2;
225                             VV    = Yt + Fp*eps;
226                             FF    = Fp + Geps + 2.0*Heps2;
227                             Vd    = Cd*VV;
228                             Fd    = Cd*FF;
229                             /* Repulsion */
230                             nnn   = nnn + 4;
231                             Yt    = VFtab[nnn];
232                             Ft    = VFtab[nnn+1];
233                             Geps  = VFtab[nnn+2]*eps;
234                             Heps2 = VFtab[nnn+3]*eps2;
235                             Fp    = Ft + Geps + Heps2;
236                             VV    = Yt + Fp*eps;
237                             FF    = Fp + Geps + 2.0*Heps2;
238                             Vr    = Cr*VV;
239                             Fr    = Cr*FF;
240                             V     = Vd + Vr;
241                             F     = -lamfac*(Fd + Fr)*tabscale;
242                         }
243                         break;
244                     case ewt93:
245                         if (r <= 0)
246                         {
247                             wall_error(i,x,r);
248                         }
249                         r1 = 1/r;
250                         r2 = r1*r1;
251                         r4 = r2*r2;
252                         Vd = fac_d[w]*Cd*r2*r1;
253                         Vr = fac_r[w]*Cr*r4*r4*r1;
254                         V  = Vr - Vd;
255                         F  = lamfac*(9*Vr - 3*Vd)*r1;
256                         break;
257                     case ewt104:
258                         if (r <= 0)
259                         {
260                             wall_error(i,x,r);
261                         }
262                         r1 = 1/r;
263                         r2 = r1*r1;
264                         r4 = r2*r2;
265                         Vd = fac_d[w]*Cd*r4;
266                         Vr = fac_r[w]*Cr*r4*r4*r2;
267                         V  = Vr - Vd;
268                         F  = lamfac*(10*Vr - 4*Vd)*r1;
269                         break;
270                     case ewt126:
271                         if (r <= 0)
272                         {
273                             wall_error(i,x,r);
274                         }
275                         r1 = 1/r;
276                         r2 = r1*r1;
277                         r4 = r2*r2;
278                         Vd = Cd*r4*r2;
279                         Vr = Cr*r4*r4*r4;
280                         V  = Vr - Vd;
281                         F  = lamfac*(12*Vr - 6*Vd)*r1;
282                         break;
283                     default:
284                         break;
285                     }
286                     if (mr > 0)
287                     {
288                         V += mr*F;
289                     }
290                     if (w == 1)
291                     {
292                         F = -F;
293                     }
294                     Vlj[ggid] += lamfac*V;
295                     Vtot      += V;
296                     f[i][ZZ]  += F;
297                     /* Because of the single sum virial calculation we need
298                      * to add  the full virial contribution of the walls.
299                      * Since the force only has a z-component, there is only
300                      * a contribution to the z component of the virial tensor.
301                      * We could also determine the virial contribution directly,
302                      * which would be cheaper here, but that would require extra
303                      * communication for f_novirsum for with virtual sites
304                      * in parallel.
305                      */
306                     xf_z[XX]  -= x[i][XX]*F;
307                     xf_z[YY]  -= x[i][YY]*F;
308                     xf_z[ZZ]  -= wall_z[w]*F;
309                 }
310             }
311         }
312         if (md->nPerturbed)
313         {
314             dvdlambda += (lam==0 ? -1 : 1)*Vtot;
315         }
316         
317         inc_nrnb(nrnb,eNR_WALLS,md->homenr);
318     }
319
320     for(i=0; i<DIM; i++)
321     {
322         fr->vir_wall_z[i] = -0.5*xf_z[i];
323     }
324
325     return dvdlambda;
326 }