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