66a1036bdcfe32a71b33a8ffc0df7840fb9fec43
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / topshake.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  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gmxpre.h"
39
40 #include <ctype.h>
41 #include <math.h>
42
43 #include "gromacs/math/units.h"
44 #include "readir.h"
45 #include "gromacs/legacyheaders/typedefs.h"
46 #include "topshake.h"
47 #include "toppush.h"
48 #include "toputil.h"
49 #include "topdirs.h"
50 #include "gromacs/utility/smalloc.h"
51 #include "gromacs/utility/fatalerror.h"
52
53 static void copy_bond (t_params *pr, int to, int from)
54 /* copies an entry in a bond list to another position.
55  * does no allocing or freeing of memory
56  */
57 {
58     /*memcpy((char*) &(pr->param[to]),(char*) &(pr->param[from]),
59        (size_t)sizeof(pr->param[from]));*/
60     int i;
61
62     if (to != from)
63     {
64         range_check(to, 0, pr->nr);
65         range_check(from, 0, pr->nr);
66         for (i = 0; (i < MAXATOMLIST); i++)
67         {
68             pr->param[to].a[i] = pr->param[from].a[i];
69         }
70         for (i = 0; (i < MAXFORCEPARAM); i++)
71         {
72             pr->param[to].c[i] = pr->param[from].c[i];
73         }
74         for (i = 0; (i < MAXSLEN); i++)
75         {
76             pr->param[to].s[i] = pr->param[from].s[i];
77         }
78     }
79 }
80
81 static int count_hydrogens (char ***atomname, int nra, atom_id a[])
82 {
83     int  i, nh;
84
85     if (!atomname)
86     {
87         gmx_fatal(FARGS, "Cannot call count_hydrogens with no atomname (%s %d)",
88                   __FILE__, __LINE__);
89     }
90
91     nh = 0;
92     for (i = 0; (i < nra); i++)
93     {
94         if (toupper(**(atomname[a[i]])) == 'H')
95         {
96             nh++;
97         }
98     }
99
100     return nh;
101 }
102
103 void make_shake (t_params plist[], t_atoms *atoms, int nshake)
104 {
105     char          ***info = atoms->atomname;
106     t_params        *pr;
107     t_params        *bonds;
108     t_param          p, *bond, *ang;
109     real             b_ij, b_jk;
110     int              nb, b, i, j, ftype, ftype_a;
111     gmx_bool         bFound;
112
113     if (nshake != eshNONE)
114     {
115         switch (nshake)
116         {
117             case eshHBONDS:
118                 printf("turning H bonds into constraints...\n");
119                 break;
120             case eshALLBONDS:
121                 printf("turning all bonds into constraints...\n");
122                 break;
123             case eshHANGLES:
124                 printf("turning all bonds and H angles into constraints...\n");
125                 break;
126             case eshALLANGLES:
127                 printf("turning all bonds and angles into constraints...\n");
128                 break;
129             default:
130                 gmx_fatal(FARGS, "Invalid option for make_shake (%d)", nshake);
131         }
132
133         if ((nshake == eshHANGLES) || (nshake == eshALLANGLES))
134         {
135             /* Add all the angles with hydrogens to the shake list
136              * and remove them from the bond list
137              */
138             for (ftype = 0; (ftype < F_NRE); ftype++)
139             {
140                 if (interaction_function[ftype].flags & IF_BTYPE)
141                 {
142                     bonds = &(plist[ftype]);
143
144                     for (ftype_a = 0; (bonds->nr > 0 && ftype_a < F_NRE); ftype_a++)
145                     {
146                         if (interaction_function[ftype_a].flags & IF_ATYPE)
147                         {
148                             pr = &(plist[ftype_a]);
149
150                             for (i = 0; (i < pr->nr); )
151                             {
152                                 int numhydrogens;
153
154                                 ang = &(pr->param[i]);
155 #ifdef DEBUG
156                                 printf("Angle: %d-%d-%d\n", ang->AI, ang->AJ, ang->AK);
157 #endif
158                                 numhydrogens = count_hydrogens(info, 3, ang->a);
159                                 if ((nshake == eshALLANGLES) ||
160                                     (numhydrogens > 1) ||
161                                     (numhydrogens == 1 && toupper(**(info[ang->a[1]])) == 'O'))
162                                 {
163                                     /* Can only add hydrogen angle shake, if the two bonds
164                                      * are constrained.
165                                      * append this angle to the shake list
166                                      */
167                                     p.AI = ang->AI;
168                                     p.AJ = ang->AK;
169
170                                     /* Calculate length of constraint */
171                                     bFound = FALSE;
172                                     b_ij   = b_jk = 0.0;
173                                     for (j = 0; !bFound && (j < bonds->nr); j++)
174                                     {
175                                         bond = &(bonds->param[j]);
176                                         if (((bond->AI == ang->AI) &&
177                                              (bond->AJ == ang->AJ)) ||
178                                             ((bond->AI == ang->AJ) &&
179                                              (bond->AJ == ang->AI)))
180                                         {
181                                             b_ij = bond->C0;
182                                         }
183                                         if (((bond->AI == ang->AK) &&
184                                              (bond->AJ == ang->AJ)) ||
185                                             ((bond->AI == ang->AJ) &&
186                                              (bond->AJ == ang->AK)))
187                                         {
188                                             b_jk = bond->C0;
189                                         }
190                                         bFound = (b_ij != 0.0) && (b_jk != 0.0);
191                                     }
192                                     if (bFound)
193                                     {
194                                         /* apply law of cosines */
195                                         p.C0 = sqrt( b_ij*b_ij + b_jk*b_jk -
196                                                      2.0*b_ij*b_jk*cos(DEG2RAD*ang->C0) );
197                                         p.C1 = p.C0;
198 #ifdef DEBUG
199                                         printf("p: %d, q: %d, dist: %12.5e\n", p.AI, p.AJ, p.C0);
200 #endif
201                                         add_param_to_list (&(plist[F_CONSTR]), &p);
202                                         /* move the last bond to this position */
203                                         copy_bond (pr, i, pr->nr-1);
204                                         /* should free memory here!! */
205                                         pr->nr--;
206                                     }
207                                 }
208                                 else
209                                 {
210                                     i++;
211                                 }
212                             }
213                         } /* if IF_ATYPE */
214                     }     /* for ftype_A */
215                 }         /* if IF_BTYPE */
216             }             /* for ftype */
217         }                 /* if shake angles */
218
219         /* Add all the bonds with hydrogens to the shake list
220          * and remove them from the bond list
221          */
222         for (ftype = 0; (ftype < F_NRE); ftype++)
223         {
224             if (interaction_function[ftype].flags & IF_BTYPE)
225             {
226                 pr = &(plist[ftype]);
227                 j  = 0;
228                 for (i = 0; i < pr->nr; i++)
229                 {
230                     if ( (nshake != eshHBONDS) ||
231                          (count_hydrogens (info, 2, pr->param[i].a) > 0) )
232                     {
233                         /* append this bond to the shake list */
234                         p.AI = pr->param[i].AI;
235                         p.AJ = pr->param[i].AJ;
236                         p.C0 = pr->param[i].C0;
237                         p.C1 = pr->param[i].C2;
238                         add_param_to_list (&(plist[F_CONSTR]), &p);
239                     }
240                     else
241                     {
242                         copy_bond(pr, j++, i);
243                     }
244                 }
245                 pr->nr = j;
246             }
247         }
248     }
249 }