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