More clear message for undefined pullgroups.
[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 if (g != 0 && strcmp(pgnames[g], "") == 0)
262         {
263             gmx_fatal(FARGS, "Group pull_group%d required by grompp was undefined.",g);
264         }
265         else
266         {
267             ig        = search_string(pgnames[g], grps->nr, gnames);
268             pgrp->nat = grps->index[ig+1] - grps->index[ig];
269         }
270         if (pgrp->nat > 0)
271         {
272             fprintf(stderr, "Pull group %d '%s' has %d atoms\n",
273                     g, pgnames[g], pgrp->nat);
274             snew(pgrp->ind, pgrp->nat);
275             for (i = 0; i < pgrp->nat; i++)
276             {
277                 pgrp->ind[i] = grps->a[grps->index[ig]+i];
278             }
279
280             if (pull->eGeom == epullgCYL && g == 0 && pgrp->nweight > 0)
281             {
282                 gmx_fatal(FARGS, "Weights are not supported for the reference group with cylinder pulling");
283             }
284             if (pgrp->nweight > 0 && pgrp->nweight != pgrp->nat)
285             {
286                 gmx_fatal(FARGS, "Number of weights (%d) for pull group %d '%s' does not match the number of atoms (%d)",
287                           pgrp->nweight, g, pgnames[g], pgrp->nat);
288             }
289
290             if (pgrp->nat == 1)
291             {
292                 /* No pbc is required for this group */
293                 pgrp->pbcatom = -1;
294             }
295             else
296             {
297                 if (pgrp->pbcatom > 0)
298                 {
299                     pgrp->pbcatom -= 1;
300                 }
301                 else if (pgrp->pbcatom == 0)
302                 {
303                     pgrp->pbcatom = pgrp->ind[(pgrp->nat-1)/2];
304                 }
305                 else
306                 {
307                     /* Use cosine weighting */
308                     pgrp->pbcatom = -1;
309                 }
310             }
311
312             if (g > 0 && pull->eGeom != epullgDIST)
313             {
314                 for (d = 0; d < DIM; d++)
315                 {
316                     if (pgrp->vec[d] != 0 && pull->dim[d] == 0)
317                     {
318                         gmx_fatal(FARGS, "ERROR: pull_vec%d has non-zero %c-component while pull_dim in N\n", g, 'x'+d);
319                     }
320                 }
321             }
322
323             if ((pull->eGeom == epullgDIR || pull->eGeom == epullgCYL) &&
324                 g > 0 && norm2(pgrp->vec) == 0)
325             {
326                 gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s",
327                           g, EPULLGEOM(pull->eGeom));
328             }
329             if ((pull->eGeom == epullgPOS) && pgrp->rate != 0 &&
330                 g > 0 && norm2(pgrp->vec) == 0)
331             {
332                 gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s and non-zero rate",
333                           g, EPULLGEOM(pull->eGeom));
334             }
335         }
336         else
337         {
338             if (g == 0)
339             {
340                 if (pull->eGeom == epullgCYL)
341                 {
342                     gmx_fatal(FARGS, "Absolute reference groups are not supported with geometry %s", EPULLGEOM(pull->eGeom));
343                 }
344             }
345             else
346             {
347                 gmx_fatal(FARGS, "Pull group %d '%s' is empty", g, pgnames[g]);
348             }
349             pgrp->pbcatom = -1;
350         }
351     }
352 }
353
354 void set_pull_init(t_inputrec *ir, gmx_mtop_t *mtop, rvec *x, matrix box, real lambda,
355                    const output_env_t oenv, gmx_bool bStart)
356 {
357     t_mdatoms *md;
358     t_pull    *pull;
359     t_pullgrp *pgrp;
360     t_pbc      pbc;
361     int        ndim, g, m;
362     double     t_start, tinvrate;
363     rvec       init;
364     dvec       dr, dev;
365
366     init_pull(NULL, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0);
367     md = init_mdatoms(NULL, mtop, ir->efep);
368     atoms2md(mtop, ir, 0, NULL, 0, mtop->natoms, md);
369     if (ir->efep)
370     {
371         update_mdatoms(md, lambda);
372     }
373     pull = ir->pull;
374     if (pull->eGeom == epullgPOS)
375     {
376         ndim = 3;
377     }
378     else
379     {
380         ndim = 1;
381     }
382
383     set_pbc(&pbc, ir->ePBC, box);
384
385     t_start = ir->init_t + ir->init_step*ir->delta_t;
386
387     pull_calc_coms(NULL, pull, md, &pbc, t_start, x, NULL);
388
389     fprintf(stderr, "Pull group  natoms  pbc atom  distance at start     reference at t=0\n");
390     for (g = 0; g < pull->ngrp+1; g++)
391     {
392         pgrp = &pull->grp[g];
393         fprintf(stderr, "%8d  %8d  %8d ", g, pgrp->nat, pgrp->pbcatom+1);
394         copy_rvec(pgrp->init, init);
395         clear_rvec(pgrp->init);
396         if (g > 0)
397         {
398             if (pgrp->rate == 0)
399             {
400                 tinvrate = 0;
401             }
402             else
403             {
404                 tinvrate = t_start/pgrp->rate;
405             }
406             get_pullgrp_distance(pull, &pbc, g, 0, dr, dev);
407             for (m = 0; m < DIM; m++)
408             {
409                 if (m < ndim)
410                 {
411                     fprintf(stderr, " %6.3f", dev[m]);
412                 }
413                 else
414                 {
415                     fprintf(stderr, "       ");
416                 }
417             }
418             fprintf(stderr, " ");
419             for (m = 0; m < DIM; m++)
420             {
421                 if (bStart)
422                 {
423                     pgrp->init[m] = init[m] + dev[m]
424                         - tinvrate*(pull->eGeom == epullgPOS ? pgrp->vec[m] : 1);
425                 }
426                 else
427                 {
428                     pgrp->init[m] = init[m];
429                 }
430                 if (m < ndim)
431                 {
432                     fprintf(stderr, " %6.3f", pgrp->init[m]);
433                 }
434                 else
435                 {
436                     fprintf(stderr, "       ");
437                 }
438             }
439         }
440         fprintf(stderr, "\n");
441     }
442 }