Fixing copyright issues and code contributors
[alexxy/gromacs.git] / src / kernel / readpull.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-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012,2013, 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 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <string.h>
43 #include <stdlib.h>
44 #include "sysstuff.h"
45 #include "princ.h"
46 #include "futil.h"
47 #include "statutil.h"
48 #include "vec.h"
49 #include "smalloc.h"
50 #include "typedefs.h"
51 #include "names.h"
52 #include "gmx_fatal.h"
53 #include "macros.h"
54 #include "index.h"
55 #include "symtab.h"
56 #include "readinp.h"
57 #include "readir.h"
58 #include <string.h>
59 #include "mdatoms.h"
60 #include "pbc.h"
61 #include "pull.h"
62
63
64 static char pulldim[STRLEN];
65
66 static void string2dvec(char buf[], dvec nums)
67 {
68   if (sscanf(buf,"%lf%lf%lf",&nums[0],&nums[1],&nums[2]) != 3)
69     gmx_fatal(FARGS,"Expected three numbers at input line %s",buf);
70 }
71
72 static void init_pullgrp(t_pullgrp *pg,char *wbuf,
73                          gmx_bool bRef,int eGeom,char *s_vec)
74 {
75   double d;
76   int    n,m;
77   dvec   vec;
78
79   pg->nweight = 0;
80   while (sscanf(wbuf,"%lf %n",&d,&n) == 1) {
81     if (pg->nweight % 100 == 0) {
82       srenew(pg->weight,pg->nweight+100);
83     }
84     pg->weight[pg->nweight++] = d;
85     wbuf += n;
86   }
87   if (!bRef) {
88     if (eGeom == epullgDIST) {
89       clear_dvec(vec);
90     } else {
91       string2dvec(s_vec,vec);
92       if (eGeom == epullgDIR || eGeom == epullgCYL || 
93           (eGeom == epullgPOS && dnorm(vec) != 0))
94         /* Normalize the direction vector */
95         dsvmul(1/dnorm(vec),vec,vec);
96     }
97     for(m=0; m<DIM; m++)
98       pg->vec[m] = vec[m];
99   }
100 }
101
102 char **read_pullparams(int *ninp_p,t_inpfile **inp_p,
103                        t_pull *pull,gmx_bool *bStart,
104                        warninp_t wi) 
105 {
106   int  ninp,nerror=0,i,nchar,ndim,nscan,m;
107   t_inpfile *inp;
108   const char *tmp;
109   char **grpbuf;
110   char dummy[STRLEN],buf[STRLEN],init[STRLEN];
111   const char *init_def1="0.0",*init_def3="0.0 0.0 0.0";
112   char wbuf[STRLEN],VecTemp[STRLEN];
113   dvec vec;
114
115   t_pullgrp *pgrp;
116
117   ninp   = *ninp_p;
118   inp    = *inp_p;
119
120   /* read pull parameters */
121   CTYPE("Pull geometry: distance, direction, cylinder or position");
122   EETYPE("pull_geometry",   pull->eGeom, epullg_names);
123   CTYPE("Select components for the pull vector. default: Y Y Y");
124   STYPE("pull_dim",         pulldim, "Y Y Y");
125   CTYPE("Cylinder radius for dynamic reaction force groups (nm)");
126   RTYPE("pull_r1",          pull->cyl_r1, 1.0);
127   CTYPE("Switch from r1 to r0 in case of dynamic reaction force");
128   RTYPE("pull_r0",          pull->cyl_r0, 1.5);
129   RTYPE("pull_constr_tol",  pull->constr_tol, 1E-6);
130   EETYPE("pull_start",      *bStart, yesno_names);
131   ITYPE("pull_nstxout",     pull->nstxout, 10);
132   ITYPE("pull_nstfout",     pull->nstfout,  1);
133   CTYPE("Number of pull groups");
134   ITYPE("pull_ngroups",     pull->ngrp,1);
135
136   if (pull->cyl_r1 > pull->cyl_r0) {
137     warning_error(wi,"pull_r1 > pull_r0");
138   }
139
140   if (pull->ngrp < 1) {
141     gmx_fatal(FARGS,"pull_ngroups should be >= 1");
142   }
143   
144   snew(pull->grp,pull->ngrp+1);
145
146   if (pull->eGeom == epullgPOS) {
147     ndim = 3;
148   } else {
149     ndim = 1;
150   }
151
152   /* pull group options */
153   CTYPE("Group name, weight (default all 1), vector, init, rate (nm/ps), kJ/(mol*nm^2)");
154   /* Read the pull groups */
155   snew(grpbuf,pull->ngrp+1);
156   for(i=0; i<pull->ngrp+1; i++) {
157     pgrp = &pull->grp[i];
158     snew(grpbuf[i],STRLEN);
159     sprintf(buf,"pull_group%d",i);
160     STYPE(buf,              grpbuf[i], "");
161     sprintf(buf,"pull_weights%d",i);
162     STYPE(buf,              wbuf, "");
163     sprintf(buf,"pull_pbcatom%d",i);
164     ITYPE(buf,              pgrp->pbcatom, 0);
165     if (i > 0) {
166       sprintf(buf,"pull_vec%d",i);
167       STYPE(buf,              VecTemp, "0.0 0.0 0.0");
168       sprintf(buf,"pull_init%d",i);
169       STYPE(buf,              init, ndim==1 ? init_def1 : init_def3);
170       nscan = sscanf(init,"%lf %lf %lf",&vec[0],&vec[1],&vec[2]);
171       if (nscan != ndim) {
172         fprintf(stderr,"ERROR: %s should have %d components\n",buf,ndim);
173         nerror++;
174       }
175       for(m=0; m<DIM; m++) {
176         pgrp->init[m] = (m<ndim ? vec[m] : 0.0);
177       }
178       sprintf(buf,"pull_rate%d",i);
179       RTYPE(buf,              pgrp->rate, 0.0);
180       sprintf(buf,"pull_k%d",i);
181       RTYPE(buf,              pgrp->k, 0.0);
182       sprintf(buf,"pull_kB%d",i);
183       RTYPE(buf,              pgrp->kB, pgrp->k);
184     }
185
186     /* Initialize the pull group */
187     init_pullgrp(pgrp,wbuf,i==0,pull->eGeom,VecTemp);
188   }
189   
190   *ninp_p   = ninp;
191   *inp_p    = inp;
192
193   return grpbuf;
194 }
195
196 void make_pull_groups(t_pull *pull,char **pgnames,t_blocka *grps,char **gnames)
197 {
198   int  d,nchar,g,ig=-1,i;
199   char *ptr,pulldim1[STRLEN];
200   t_pullgrp *pgrp;
201
202   ptr = pulldim;
203   i = 0;
204   for(d=0; d<DIM; d++) {
205     if (sscanf(ptr,"%s%n",pulldim1,&nchar) != 1)
206       gmx_fatal(FARGS,"Less than 3 pull dimensions given in pull_dim: '%s'",
207                 pulldim);
208     
209     if (gmx_strncasecmp(pulldim1,"N",1) == 0) {
210       pull->dim[d] = 0;
211     } else if (gmx_strncasecmp(pulldim1,"Y",1) == 0) {
212       pull->dim[d] = 1;
213       i++;
214     } else {
215       gmx_fatal(FARGS,"Please use Y(ES) or N(O) for pull_dim only (not %s)",
216                 pulldim1);
217     }
218     ptr += nchar;
219   }
220   if (i == 0)
221     gmx_fatal(FARGS,"All entries in pull_dim are N");
222
223   for(g=0; g<pull->ngrp+1; g++) {
224     pgrp = &pull->grp[g];
225     if (g == 0 && strcmp(pgnames[g],"") == 0) {
226       pgrp->nat = 0;
227     } else {
228       ig = search_string(pgnames[g],grps->nr,gnames);
229       pgrp->nat = grps->index[ig+1] - grps->index[ig];
230     }
231     if (pgrp->nat > 0) {
232       fprintf(stderr,"Pull group %d '%s' has %d atoms\n",
233               g,pgnames[g],pgrp->nat);
234       snew(pgrp->ind,pgrp->nat);
235       for(i=0; i<pgrp->nat; i++)
236         pgrp->ind[i] = grps->a[grps->index[ig]+i];
237
238       if (pull->eGeom == epullgCYL && g == 0 && pgrp->nweight > 0)
239         gmx_fatal(FARGS,"Weights are not supported for the reference group with cylinder pulling");
240       if (pgrp->nweight > 0 && pgrp->nweight != pgrp->nat)
241         gmx_fatal(FARGS,"Number of weights (%d) for pull group %d '%s' does not match the number of atoms (%d)",
242                   pgrp->nweight,g,pgnames[g],pgrp->nat);
243
244       if (pgrp->nat == 1) {
245         /* No pbc is required for this group */
246         pgrp->pbcatom = -1;
247       } else {
248         if (pgrp->pbcatom > 0) {
249           pgrp->pbcatom -= 1;
250         } else if (pgrp->pbcatom == 0) {
251           pgrp->pbcatom = pgrp->ind[(pgrp->nat-1)/2];
252         } else {
253           /* Use cosine weighting */
254           pgrp->pbcatom = -1;
255         }
256       }
257
258       if (g > 0 && pull->eGeom != epullgDIST) {
259         for(d=0; d<DIM; d++) {
260           if (pgrp->vec[d] != 0 && pull->dim[d] == 0) {
261             gmx_fatal(FARGS,"ERROR: pull_vec%d has non-zero %c-component while pull_dim in N\n",g,'x'+d);
262           }
263         }
264       }
265
266       if ((pull->eGeom == epullgDIR || pull->eGeom == epullgCYL) &&
267           g > 0 && norm2(pgrp->vec) == 0)
268         gmx_fatal(FARGS,"pull_vec%d can not be zero with geometry %s",
269                   g,EPULLGEOM(pull->eGeom));
270       if ((pull->eGeom == epullgPOS) && pgrp->rate != 0 &&
271           g > 0 && norm2(pgrp->vec) == 0)
272         gmx_fatal(FARGS,"pull_vec%d can not be zero with geometry %s and non-zero rate",
273                   g,EPULLGEOM(pull->eGeom));
274     } else {
275       if (g == 0) {
276         if (pull->eGeom == epullgCYL)
277           gmx_fatal(FARGS,"Absolute reference groups are not supported with geometry %s",EPULLGEOM(pull->eGeom));
278       } else {
279         gmx_fatal(FARGS,"Pull group %d '%s' is empty",g,pgnames[g]);
280       }
281       pgrp->pbcatom = -1;
282     }
283   }
284 }
285
286 void set_pull_init(t_inputrec *ir,gmx_mtop_t *mtop,rvec *x,matrix box,real lambda,
287                    const output_env_t oenv,gmx_bool bStart)
288 {
289   t_mdatoms *md;
290   t_pull    *pull;
291   t_pullgrp *pgrp;
292   t_pbc     pbc;
293   int       ndim,g,m;
294   double    t_start,tinvrate;
295   rvec      init;
296   dvec      dr,dev;
297
298   init_pull(NULL,ir,0,NULL,mtop,NULL,oenv,lambda,FALSE,0); 
299   md = init_mdatoms(NULL,mtop,ir->efep);
300   atoms2md(mtop,ir,0,NULL,0,mtop->natoms,md);
301   if (ir->efep)
302   {
303     update_mdatoms(md,lambda);
304   }
305   pull = ir->pull;
306   if (pull->eGeom == epullgPOS)
307     ndim = 3;
308   else
309     ndim = 1;
310
311   set_pbc(&pbc,ir->ePBC,box);
312
313   t_start = ir->init_t + ir->init_step*ir->delta_t;
314
315   pull_calc_coms(NULL,pull,md,&pbc,t_start,x,NULL);
316
317   fprintf(stderr,"Pull group  natoms  pbc atom  distance at start     reference at t=0\n");
318   for(g=0; g<pull->ngrp+1; g++) {
319     pgrp = &pull->grp[g];
320     fprintf(stderr,"%8d  %8d  %8d ",g,pgrp->nat,pgrp->pbcatom+1);
321     copy_rvec(pgrp->init,init);
322     clear_rvec(pgrp->init);
323     if (g > 0) {
324       if (pgrp->rate == 0)
325         tinvrate = 0;
326       else
327         tinvrate = t_start/pgrp->rate;
328       get_pullgrp_distance(pull,&pbc,g,0,dr,dev);
329       for(m=0; m<DIM; m++) {
330         if (m < ndim)
331           fprintf(stderr," %6.3f",dev[m]);
332         else
333           fprintf(stderr,"       ");
334       }
335       fprintf(stderr," ");
336       for(m=0; m<DIM; m++) {
337         if (bStart)
338           pgrp->init[m] = init[m] + dev[m]
339             - tinvrate*(pull->eGeom==epullgPOS ? pgrp->vec[m] : 1);
340         else
341           pgrp->init[m] = init[m];
342         if (m < ndim)
343           fprintf(stderr," %6.3f",pgrp->init[m]);
344         else
345           fprintf(stderr,"       ");
346       }
347     }
348     fprintf(stderr,"\n");
349   }
350 }