Merge branch 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 "index.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     {
67         gmx_fatal(FARGS, "Expected three numbers at input line %s", buf);
68     }
69 }
70
71 static void init_pullgrp(t_pullgrp *pg, char *wbuf,
72                          gmx_bool bRef, int eGeom, char *s_vec)
73 {
74     double d;
75     int    n, m;
76     dvec   vec;
77
78     pg->nweight = 0;
79     while (sscanf(wbuf, "%lf %n", &d, &n) == 1)
80     {
81         if (pg->nweight % 100 == 0)
82         {
83             srenew(pg->weight, pg->nweight+100);
84         }
85         pg->weight[pg->nweight++] = d;
86         wbuf += n;
87     }
88     if (!bRef)
89     {
90         if (eGeom == epullgDIST)
91         {
92             clear_dvec(vec);
93         }
94         else
95         {
96             string2dvec(s_vec, vec);
97             if (eGeom == epullgDIR || eGeom == epullgCYL ||
98                 (eGeom == epullgPOS && dnorm(vec) != 0))
99             {
100                 /* Normalize the direction vector */
101                 dsvmul(1/dnorm(vec), vec, vec);
102             }
103         }
104         for (m = 0; m < DIM; m++)
105         {
106             pg->vec[m] = vec[m];
107         }
108     }
109 }
110
111 char **read_pullparams(int *ninp_p, t_inpfile **inp_p,
112                        t_pull *pull, gmx_bool *bStart,
113                        warninp_t wi)
114 {
115     int         ninp, nerror = 0, i, nchar, ndim, nscan, m;
116     t_inpfile  *inp;
117     const char *tmp;
118     char      **grpbuf;
119     char        dummy[STRLEN], buf[STRLEN], init[STRLEN];
120     const char *init_def1 = "0.0", *init_def3 = "0.0 0.0 0.0";
121     char        wbuf[STRLEN], VecTemp[STRLEN];
122     dvec        vec;
123
124     t_pullgrp  *pgrp;
125
126     ninp   = *ninp_p;
127     inp    = *inp_p;
128
129     /* read pull parameters */
130     CTYPE("Pull geometry: distance, direction, cylinder or position");
131     EETYPE("pull_geometry",   pull->eGeom, epullg_names);
132     CTYPE("Select components for the pull vector. default: Y Y Y");
133     STYPE("pull_dim",         pulldim, "Y Y Y");
134     CTYPE("Cylinder radius for dynamic reaction force groups (nm)");
135     RTYPE("pull_r1",          pull->cyl_r1, 1.0);
136     CTYPE("Switch from r1 to r0 in case of dynamic reaction force");
137     RTYPE("pull_r0",          pull->cyl_r0, 1.5);
138     RTYPE("pull_constr_tol",  pull->constr_tol, 1E-6);
139     EETYPE("pull_start",      *bStart, yesno_names);
140     ITYPE("pull_nstxout",     pull->nstxout, 10);
141     ITYPE("pull_nstfout",     pull->nstfout,  1);
142     CTYPE("Number of pull groups");
143     ITYPE("pull_ngroups",     pull->ngrp, 1);
144
145     if (pull->cyl_r1 > pull->cyl_r0)
146     {
147         warning_error(wi, "pull_r1 > pull_r0");
148     }
149
150     if (pull->ngrp < 1)
151     {
152         gmx_fatal(FARGS, "pull_ngroups should be >= 1");
153     }
154
155     snew(pull->grp, pull->ngrp+1);
156
157     if (pull->eGeom == epullgPOS)
158     {
159         ndim = 3;
160     }
161     else
162     {
163         ndim = 1;
164     }
165
166     /* pull group options */
167     CTYPE("Group name, weight (default all 1), vector, init, rate (nm/ps), kJ/(mol*nm^2)");
168     /* Read the pull groups */
169     snew(grpbuf, pull->ngrp+1);
170     for (i = 0; i < pull->ngrp+1; i++)
171     {
172         pgrp = &pull->grp[i];
173         snew(grpbuf[i], STRLEN);
174         sprintf(buf, "pull_group%d", i);
175         STYPE(buf,              grpbuf[i], "");
176         sprintf(buf, "pull_weights%d", i);
177         STYPE(buf,              wbuf, "");
178         sprintf(buf, "pull_pbcatom%d", i);
179         ITYPE(buf,              pgrp->pbcatom, 0);
180         if (i > 0)
181         {
182             sprintf(buf, "pull_vec%d", i);
183             STYPE(buf,              VecTemp, "0.0 0.0 0.0");
184             sprintf(buf, "pull_init%d", i);
185             STYPE(buf,              init, ndim == 1 ? init_def1 : init_def3);
186             nscan = sscanf(init, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]);
187             if (nscan != ndim)
188             {
189                 fprintf(stderr, "ERROR: %s should have %d components\n", buf, ndim);
190                 nerror++;
191             }
192             for (m = 0; m < DIM; m++)
193             {
194                 pgrp->init[m] = (m < ndim ? vec[m] : 0.0);
195             }
196             sprintf(buf, "pull_rate%d", i);
197             RTYPE(buf,              pgrp->rate, 0.0);
198             sprintf(buf, "pull_k%d", i);
199             RTYPE(buf,              pgrp->k, 0.0);
200             sprintf(buf, "pull_kB%d", i);
201             RTYPE(buf,              pgrp->kB, pgrp->k);
202         }
203
204         /* Initialize the pull group */
205         init_pullgrp(pgrp, wbuf, i == 0, pull->eGeom, VecTemp);
206     }
207
208     *ninp_p   = ninp;
209     *inp_p    = inp;
210
211     return grpbuf;
212 }
213
214 void make_pull_groups(t_pull *pull, char **pgnames, t_blocka *grps, char **gnames)
215 {
216     int        d, nchar, g, ig = -1, i;
217     char      *ptr, pulldim1[STRLEN];
218     t_pullgrp *pgrp;
219
220     ptr = pulldim;
221     i   = 0;
222     for (d = 0; d < DIM; d++)
223     {
224         if (sscanf(ptr, "%s%n", pulldim1, &nchar) != 1)
225         {
226             gmx_fatal(FARGS, "Less than 3 pull dimensions given in pull_dim: '%s'",
227                       pulldim);
228         }
229
230         if (gmx_strncasecmp(pulldim1, "N", 1) == 0)
231         {
232             pull->dim[d] = 0;
233         }
234         else if (gmx_strncasecmp(pulldim1, "Y", 1) == 0)
235         {
236             pull->dim[d] = 1;
237             i++;
238         }
239         else
240         {
241             gmx_fatal(FARGS, "Please use Y(ES) or N(O) for pull_dim only (not %s)",
242                       pulldim1);
243         }
244         ptr += nchar;
245     }
246     if (i == 0)
247     {
248         gmx_fatal(FARGS, "All entries in pull_dim are N");
249     }
250
251     for (g = 0; g < pull->ngrp+1; g++)
252     {
253         pgrp = &pull->grp[g];
254         if (g == 0 && strcmp(pgnames[g], "") == 0)
255         {
256             pgrp->nat = 0;
257         }
258         else
259         {
260             ig        = search_string(pgnames[g], grps->nr, gnames);
261             pgrp->nat = grps->index[ig+1] - grps->index[ig];
262         }
263         if (pgrp->nat > 0)
264         {
265             fprintf(stderr, "Pull group %d '%s' has %d atoms\n",
266                     g, pgnames[g], pgrp->nat);
267             snew(pgrp->ind, pgrp->nat);
268             for (i = 0; i < pgrp->nat; i++)
269             {
270                 pgrp->ind[i] = grps->a[grps->index[ig]+i];
271             }
272
273             if (pull->eGeom == epullgCYL && g == 0 && pgrp->nweight > 0)
274             {
275                 gmx_fatal(FARGS, "Weights are not supported for the reference group with cylinder pulling");
276             }
277             if (pgrp->nweight > 0 && pgrp->nweight != pgrp->nat)
278             {
279                 gmx_fatal(FARGS, "Number of weights (%d) for pull group %d '%s' does not match the number of atoms (%d)",
280                           pgrp->nweight, g, pgnames[g], pgrp->nat);
281             }
282
283             if (pgrp->nat == 1)
284             {
285                 /* No pbc is required for this group */
286                 pgrp->pbcatom = -1;
287             }
288             else
289             {
290                 if (pgrp->pbcatom > 0)
291                 {
292                     pgrp->pbcatom -= 1;
293                 }
294                 else if (pgrp->pbcatom == 0)
295                 {
296                     pgrp->pbcatom = pgrp->ind[(pgrp->nat-1)/2];
297                 }
298                 else
299                 {
300                     /* Use cosine weighting */
301                     pgrp->pbcatom = -1;
302                 }
303             }
304
305             if (g > 0 && pull->eGeom != epullgDIST)
306             {
307                 for (d = 0; d < DIM; d++)
308                 {
309                     if (pgrp->vec[d] != 0 && pull->dim[d] == 0)
310                     {
311                         gmx_fatal(FARGS, "ERROR: pull_vec%d has non-zero %c-component while pull_dim in N\n", g, 'x'+d);
312                     }
313                 }
314             }
315
316             if ((pull->eGeom == epullgDIR || pull->eGeom == epullgCYL) &&
317                 g > 0 && norm2(pgrp->vec) == 0)
318             {
319                 gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s",
320                           g, EPULLGEOM(pull->eGeom));
321             }
322             if ((pull->eGeom == epullgPOS) && pgrp->rate != 0 &&
323                 g > 0 && norm2(pgrp->vec) == 0)
324             {
325                 gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s and non-zero rate",
326                           g, EPULLGEOM(pull->eGeom));
327             }
328         }
329         else
330         {
331             if (g == 0)
332             {
333                 if (pull->eGeom == epullgCYL)
334                 {
335                     gmx_fatal(FARGS, "Absolute reference groups are not supported with geometry %s", EPULLGEOM(pull->eGeom));
336                 }
337             }
338             else
339             {
340                 gmx_fatal(FARGS, "Pull group %d '%s' is empty", g, pgnames[g]);
341             }
342             pgrp->pbcatom = -1;
343         }
344     }
345 }
346
347 void set_pull_init(t_inputrec *ir, gmx_mtop_t *mtop, rvec *x, matrix box, real lambda,
348                    const output_env_t oenv, gmx_bool bStart)
349 {
350     t_mdatoms *md;
351     t_pull    *pull;
352     t_pullgrp *pgrp;
353     t_pbc      pbc;
354     int        ndim, g, m;
355     double     t_start, tinvrate;
356     rvec       init;
357     dvec       dr, dev;
358
359     init_pull(NULL, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0);
360     md = init_mdatoms(NULL, mtop, ir->efep);
361     atoms2md(mtop, ir, 0, NULL, 0, mtop->natoms, md);
362     if (ir->efep)
363     {
364         update_mdatoms(md, lambda);
365     }
366     pull = ir->pull;
367     if (pull->eGeom == epullgPOS)
368     {
369         ndim = 3;
370     }
371     else
372     {
373         ndim = 1;
374     }
375
376     set_pbc(&pbc, ir->ePBC, box);
377
378     t_start = ir->init_t + ir->init_step*ir->delta_t;
379
380     pull_calc_coms(NULL, pull, md, &pbc, t_start, x, NULL);
381
382     fprintf(stderr, "Pull group  natoms  pbc atom  distance at start     reference at t=0\n");
383     for (g = 0; g < pull->ngrp+1; g++)
384     {
385         pgrp = &pull->grp[g];
386         fprintf(stderr, "%8d  %8d  %8d ", g, pgrp->nat, pgrp->pbcatom+1);
387         copy_rvec(pgrp->init, init);
388         clear_rvec(pgrp->init);
389         if (g > 0)
390         {
391             if (pgrp->rate == 0)
392             {
393                 tinvrate = 0;
394             }
395             else
396             {
397                 tinvrate = t_start/pgrp->rate;
398             }
399             get_pullgrp_distance(pull, &pbc, g, 0, dr, dev);
400             for (m = 0; m < DIM; m++)
401             {
402                 if (m < ndim)
403                 {
404                     fprintf(stderr, " %6.3f", dev[m]);
405                 }
406                 else
407                 {
408                     fprintf(stderr, "       ");
409                 }
410             }
411             fprintf(stderr, " ");
412             for (m = 0; m < DIM; m++)
413             {
414                 if (bStart)
415                 {
416                     pgrp->init[m] = init[m] + dev[m]
417                         - tinvrate*(pull->eGeom == epullgPOS ? pgrp->vec[m] : 1);
418                 }
419                 else
420                 {
421                     pgrp->init[m] = init[m];
422                 }
423                 if (m < ndim)
424                 {
425                     fprintf(stderr, " %6.3f", pgrp->init[m]);
426                 }
427                 else
428                 {
429                     fprintf(stderr, "       ");
430                 }
431             }
432         }
433         fprintf(stderr, "\n");
434     }
435 }