Fix remaining copyright headers
[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, 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 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <ctype.h>
43
44 #include "sysstuff.h"
45 #include "physics.h"
46 #include "macros.h"
47 #include "readir.h"
48 #include "typedefs.h"
49 #include "topshake.h"
50 #include "toppush.h"
51 #include "toputil.h"
52 #include "topdirs.h"
53 #include "smalloc.h"
54 #include "gmx_fatal.h"
55
56 static void copy_bond (t_params *pr, int to, int from)
57 /* copies an entry in a bond list to another position.
58  * does no allocing or freeing of memory
59  */
60 {
61     /*memcpy((char*) &(pr->param[to]),(char*) &(pr->param[from]),
62        (size_t)sizeof(pr->param[from]));*/
63     int i;
64
65     if (to != from)
66     {
67         range_check(to, 0, pr->nr);
68         range_check(from, 0, pr->nr);
69         for (i = 0; (i < MAXATOMLIST); i++)
70         {
71             pr->param[to].a[i] = pr->param[from].a[i];
72         }
73         for (i = 0; (i < MAXFORCEPARAM); i++)
74         {
75             pr->param[to].c[i] = pr->param[from].c[i];
76         }
77         for (i = 0; (i < MAXSLEN); i++)
78         {
79             pr->param[to].s[i] = pr->param[from].s[i];
80         }
81     }
82 }
83
84 static int count_hydrogens (char ***atomname, int nra, atom_id a[])
85 {
86     int  i, nh;
87
88     if (!atomname)
89     {
90         gmx_fatal(FARGS, "Cannot call count_hydrogens with no atomname (%s %d)",
91                   __FILE__, __LINE__);
92     }
93
94     nh = 0;
95     for (i = 0; (i < nra); i++)
96     {
97         if (toupper(**(atomname[a[i]])) == 'H')
98         {
99             nh++;
100         }
101     }
102
103     return nh;
104 }
105
106 void make_shake (t_params plist[], t_atoms *atoms, int nshake)
107 {
108     char          ***info = atoms->atomname;
109     t_params        *pr;
110     t_params        *bonds;
111     t_param          p, *bond, *ang;
112     real             b_ij, b_jk;
113     int              nb, b, i, j, ftype, ftype_a;
114     gmx_bool         bFound;
115
116     if (nshake != eshNONE)
117     {
118         switch (nshake)
119         {
120             case eshHBONDS:
121                 printf("turning H bonds into constraints...\n");
122                 break;
123             case eshALLBONDS:
124                 printf("turning all bonds into constraints...\n");
125                 break;
126             case eshHANGLES:
127                 printf("turning all bonds and H angles into constraints...\n");
128                 break;
129             case eshALLANGLES:
130                 printf("turning all bonds and angles into constraints...\n");
131                 break;
132             default:
133                 gmx_fatal(FARGS, "Invalid option for make_shake (%d)", nshake);
134         }
135
136         if ((nshake == eshHANGLES) || (nshake == eshALLANGLES))
137         {
138             /* Add all the angles with hydrogens to the shake list
139              * and remove them from the bond list
140              */
141             for (ftype = 0; (ftype < F_NRE); ftype++)
142             {
143                 if (interaction_function[ftype].flags & IF_BTYPE)
144                 {
145                     bonds = &(plist[ftype]);
146
147                     for (ftype_a = 0; (bonds->nr > 0 && ftype_a < F_NRE); ftype_a++)
148                     {
149                         if (interaction_function[ftype_a].flags & IF_ATYPE)
150                         {
151                             pr = &(plist[ftype_a]);
152
153                             for (i = 0; (i < pr->nr); )
154                             {
155                                 int numhydrogens;
156
157                                 ang = &(pr->param[i]);
158 #ifdef DEBUG
159                                 printf("Angle: %d-%d-%d\n", ang->AI, ang->AJ, ang->AK);
160 #endif
161                                 numhydrogens = count_hydrogens(info, 3, ang->a);
162                                 if ((nshake == eshALLANGLES) ||
163                                     (numhydrogens > 1) ||
164                                     (numhydrogens == 1 && toupper(**(info[ang->a[1]])) == 'O'))
165                                 {
166                                     /* Can only add hydrogen angle shake, if the two bonds
167                                      * are constrained.
168                                      * append this angle to the shake list
169                                      */
170                                     p.AI = ang->AI;
171                                     p.AJ = ang->AK;
172
173                                     /* Calculate length of constraint */
174                                     bFound = FALSE;
175                                     b_ij   = b_jk = 0.0;
176                                     for (j = 0; !bFound && (j < bonds->nr); j++)
177                                     {
178                                         bond = &(bonds->param[j]);
179                                         if (((bond->AI == ang->AI) &&
180                                              (bond->AJ == ang->AJ)) ||
181                                             ((bond->AI == ang->AJ) &&
182                                              (bond->AJ == ang->AI)))
183                                         {
184                                             b_ij = bond->C0;
185                                         }
186                                         if (((bond->AI == ang->AK) &&
187                                              (bond->AJ == ang->AJ)) ||
188                                             ((bond->AI == ang->AJ) &&
189                                              (bond->AJ == ang->AK)))
190                                         {
191                                             b_jk = bond->C0;
192                                         }
193                                         bFound = (b_ij != 0.0) && (b_jk != 0.0);
194                                     }
195                                     if (bFound)
196                                     {
197                                         /* apply law of cosines */
198                                         p.C0 = sqrt( b_ij*b_ij + b_jk*b_jk -
199                                                      2.0*b_ij*b_jk*cos(DEG2RAD*ang->C0) );
200                                         p.C1 = p.C0;
201 #ifdef DEBUG
202                                         printf("p: %d, q: %d, dist: %12.5e\n", p.AI, p.AJ, p.C0);
203 #endif
204                                         add_param_to_list (&(plist[F_CONSTR]), &p);
205                                         /* move the last bond to this position */
206                                         copy_bond (pr, i, pr->nr-1);
207                                         /* should free memory here!! */
208                                         pr->nr--;
209                                     }
210                                 }
211                                 else
212                                 {
213                                     i++;
214                                 }
215                             }
216                         } /* if IF_ATYPE */
217                     }     /* for ftype_A */
218                 }         /* if IF_BTYPE */
219             }             /* for ftype */
220         }                 /* if shake angles */
221
222         /* Add all the bonds with hydrogens to the shake list
223          * and remove them from the bond list
224          */
225         for (ftype = 0; (ftype < F_NRE); ftype++)
226         {
227             if (interaction_function[ftype].flags & IF_BTYPE)
228             {
229                 pr = &(plist[ftype]);
230                 j  = 0;
231                 for (i = 0; i < pr->nr; i++)
232                 {
233                     if ( (nshake != eshHBONDS) ||
234                          (count_hydrogens (info, 2, pr->param[i].a) > 0) )
235                     {
236                         /* append this bond to the shake list */
237                         p.AI = pr->param[i].AI;
238                         p.AJ = pr->param[i].AJ;
239                         p.C0 = pr->param[i].C0;
240                         p.C1 = pr->param[i].C2;
241                         add_param_to_list (&(plist[F_CONSTR]), &p);
242                     }
243                     else
244                     {
245                         copy_bond(pr, j++, i);
246                     }
247                 }
248                 pr->nr = j;
249             }
250         }
251     }
252 }