98148c5a1be280b2daa8ddbad6d6e96ae7d4fbd4
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / hackblock.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) 2011,2014,2015, 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 "hackblock.h"
41
42 #include <string.h>
43
44 #include "gromacs/legacyheaders/names.h"
45 #include "gromacs/math/vec.h"
46 #include "gromacs/utility/cstringutil.h"
47 #include "gromacs/utility/fatalerror.h"
48 #include "gromacs/utility/smalloc.h"
49
50 /* these MUST correspond to the enum in hackblock.h */
51 const char *btsNames[ebtsNR] = { "bonds", "angles", "dihedrals", "impropers", "exclusions", "cmap" };
52 const int   btsNiatoms[ebtsNR] = { 2,       3,        4,           4,           2,             5 };
53
54 static void free_t_bonded(t_rbonded *rb)
55 {
56     int i;
57
58     for (i = 0; i < MAXATOMLIST; i++)
59     {
60         sfree(rb->a[i]);
61     }
62     sfree(rb->s);
63 }
64
65 static void free_t_bondeds(t_rbondeds *rbs)
66 {
67     int i;
68
69     for (i = 0; i < rbs->nb; i++)
70     {
71         free_t_bonded(&rbs->b[i]);
72     }
73     sfree(rbs->b);
74     rbs->b  = NULL;
75     rbs->nb = 0;
76 }
77
78 void free_t_restp(int nrtp, t_restp **rtp)
79 {
80     int i, j;
81
82     for (i = 0; i < nrtp; i++)
83     {
84         sfree((*rtp)[i].resname);
85         sfree((*rtp)[i].atom);
86         for (j = 0; j < (*rtp)[i].natom; j++)
87         {
88             sfree(*(*rtp)[i].atomname[j]);
89             sfree((*rtp)[i].atomname[j]);
90         }
91         sfree((*rtp)[i].atomname);
92         sfree((*rtp)[i].cgnr);
93         for (j = 0; j < ebtsNR; j++)
94         {
95             free_t_bondeds(&(*rtp)[i].rb[j]);
96         }
97     }
98     sfree(*rtp);
99 }
100
101 void free_t_hack(int nh, t_hack **h)
102 {
103     int i, j;
104
105     for (i = 0; i < nh; i++)
106     {
107         sfree((*h)[i].oname);
108         sfree((*h)[i].nname);
109         sfree((*h)[i].atom);
110         for (j = 0; j < 4; j++)
111         {
112             sfree((*h)[i].a[j]);
113         }
114     }
115     sfree(*h);
116     *h = NULL;
117 }
118
119 void free_t_hackblock(int nhb, t_hackblock **hb)
120 {
121     int i, j;
122
123     for (i = 0; i < nhb; i++)
124     {
125         sfree((*hb)[i].name);
126         free_t_hack((*hb)[i].nhack, &(*hb)[i].hack);
127         for (j = 0; j < ebtsNR; j++)
128         {
129             free_t_bondeds(&(*hb)[i].rb[j]);
130         }
131     }
132     sfree(*hb);
133 }
134
135 void clear_t_hackblock(t_hackblock *hb)
136 {
137     int i;
138
139     hb->name    = NULL;
140     hb->nhack   = 0;
141     hb->maxhack = 0;
142     hb->hack    = NULL;
143     for (i = 0; i < ebtsNR; i++)
144     {
145         hb->rb[i].nb = 0;
146         hb->rb[i].b  = NULL;
147     }
148 }
149
150 void clear_t_hack(t_hack *hack)
151 {
152     int i;
153
154     hack->nr    = 0;
155     hack->oname = NULL;
156     hack->nname = NULL;
157     hack->atom  = NULL;
158     hack->cgnr  = NOTSET;
159     hack->tp    = 0;
160     hack->nctl  = 0;
161     for (i = 0; i < 4; i++)
162     {
163         hack->a[i]  = NULL;
164     }
165     for (i = 0; i < DIM; i++)
166     {
167         hack->newx[i] = NOTSET;
168     }
169 }
170
171 #define safe_strdup(str) ((str != NULL) ? gmx_strdup(str) : NULL)
172
173 static void copy_t_rbonded(t_rbonded *s, t_rbonded *d)
174 {
175     int i;
176
177     for (i = 0; i < MAXATOMLIST; i++)
178     {
179         d->a[i] = safe_strdup(s->a[i]);
180     }
181     d->s     = safe_strdup(s->s);
182     d->match = s->match;
183 }
184
185 static gmx_bool contains_char(t_rbonded *s, char c)
186 {
187     int      i;
188     gmx_bool bRet;
189
190     bRet = FALSE;
191     for (i = 0; i < MAXATOMLIST; i++)
192     {
193         if (s->a[i] && s->a[i][0] == c)
194         {
195             bRet = TRUE;
196         }
197     }
198
199     return bRet;
200 }
201
202 int
203 rbonded_find_atoms_in_list(t_rbonded *b, t_rbonded blist[], int nlist, int natoms)
204 {
205     int      i, k;
206     int      foundPos = -1;
207     gmx_bool atomsMatch;
208
209     for (i = 0; i < nlist && foundPos < 0; i++)
210     {
211         atomsMatch = TRUE;
212         for (k = 0; k < natoms && atomsMatch; k++)
213         {
214             atomsMatch = atomsMatch && !strcmp(b->a[k], blist[i].a[k]);
215         }
216         /* Try reverse if forward match did not work */
217         if (!atomsMatch)
218         {
219             atomsMatch = TRUE;
220             for (k = 0; k < natoms && atomsMatch; k++)
221             {
222                 atomsMatch = atomsMatch && !strcmp(b->a[k], blist[i].a[natoms-1-k]);
223             }
224         }
225         if (atomsMatch)
226         {
227             foundPos = i;
228             /* If all the atoms AND all the parameters match, it is likely that
229              * the user made a copy-and-paste mistake (since it would be much cheaper
230              * to just bump the force constant 2x if you really want it twice).
231              * Since we only have the unparsed string here we can only detect
232              * EXACT matches (including identical whitespace).
233              */
234             if (!strcmp(b->s, blist[i].s))
235             {
236                 gmx_warning("Duplicate line found in or between hackblock and rtp entries");
237             }
238         }
239     }
240     return foundPos;
241 }
242
243 gmx_bool merge_t_bondeds(t_rbondeds s[], t_rbondeds d[], gmx_bool bMin, gmx_bool bPlus)
244 {
245     int      i, j;
246     gmx_bool bBondsRemoved;
247     int      nbHackblockStart;
248     int      index;
249
250     bBondsRemoved = FALSE;
251     for (i = 0; i < ebtsNR; i++)
252     {
253         if (s[i].nb > 0)
254         {
255             /* Record how many bonds we have in the destination when we start.
256              *
257              * If an entry is present in the hackblock (destination), we will
258              * not add the one from the main rtp, since the point is for hackblocks
259              * to overwrite it. However, if there is no hackblock entry we do
260              * allow multiple main rtp entries since some forcefield insist on that.
261              *
262              * We accomplish this by checking the position we find an entry in,
263              * rather than merely checking whether it exists at all.
264              * If that index is larger than the original (hackblock) destination
265              * size, it was added from the main rtp, and then we will allow more
266              * such entries. In contrast, if the entry found has a lower index
267              * it is a hackblock entry meant to override the main rtp, and then
268              * we don't add the main rtp one.
269              */
270             nbHackblockStart = d[i].nb;
271
272             /* make space */
273             srenew(d[i].b, d[i].nb + s[i].nb);
274             for (j = 0; j < s[i].nb; j++)
275             {
276                 /* Check if this bonded string already exists before adding.
277                  * We are merging from the main RTP to the hackblocks, so this
278                  * will mean the hackblocks overwrite the man RTP, as intended.
279                  */
280                 index = rbonded_find_atoms_in_list(&s[i].b[j], d[i].b, d[i].nb, btsNiatoms[i]);
281                 /* - If we did not find this interaction at all, the index will be -1,
282                  *   and then we should definitely add it to the merged hackblock and rtp.
283                  *
284                  * Alternatively, if it was found, index will be >=0.
285                  * - In case this index is lower than the original number of entries,
286                  *   it is already present as a *hackblock* entry, and those should
287                  *   always override whatever we have listed in the RTP. Thus, we
288                  *   should just keep that one and not add anything from the RTP.
289                  * - Finally, if it was found, but with an index higher than
290                  *   the original number of entries, it comes from the RTP rather
291                  *   than hackblock, and then we must have added it ourselves
292                  *   in a previous iteration. In that case it is a matter of
293                  *   several entries for the same sequence of atoms, and we allow
294                  *   that in the RTP. In this case we should simply copy all of
295                  *   them, including this one.
296                  */
297                 if (index < 0 || index >= nbHackblockStart)
298                 {
299                     if (!(bMin && contains_char(&s[i].b[j], '-'))
300                         && !(bPlus && contains_char(&s[i].b[j], '+')))
301                     {
302                         copy_t_rbonded(&s[i].b[j], &d[i].b[ d[i].nb ]);
303                         d[i].nb++;
304                     }
305                     else if (i == ebtsBONDS)
306                     {
307                         bBondsRemoved = TRUE;
308                     }
309                 }
310                 else
311                 {
312                     /* This is the common case where a hackblock entry simply
313                      * overrides the RTP, so we cannot warn here.
314                      */
315                 }
316             }
317         }
318     }
319     return bBondsRemoved;
320 }
321
322 void copy_t_restp(t_restp *s, t_restp *d)
323 {
324     int i;
325
326     *d         = *s;
327     d->resname = safe_strdup(s->resname);
328     snew(d->atom, s->natom);
329     for (i = 0; i < s->natom; i++)
330     {
331         d->atom[i] = s->atom[i];
332     }
333     snew(d->atomname, s->natom);
334     for (i = 0; i < s->natom; i++)
335     {
336         snew(d->atomname[i], 1);
337         *d->atomname[i] = safe_strdup(*s->atomname[i]);
338     }
339     snew(d->cgnr, s->natom);
340     for (i = 0; i < s->natom; i++)
341     {
342         d->cgnr[i] = s->cgnr[i];
343     }
344     for (i = 0; i < ebtsNR; i++)
345     {
346         d->rb[i].type = s->rb[i].type;
347         d->rb[i].nb   = 0;
348         d->rb[i].b    = NULL;
349     }
350     merge_t_bondeds(s->rb, d->rb, FALSE, FALSE);
351 }
352
353 void copy_t_hack(t_hack *s, t_hack *d)
354 {
355     int i;
356
357     *d       = *s;
358     d->oname = safe_strdup(s->oname);
359     d->nname = safe_strdup(s->nname);
360     if (s->atom)
361     {
362         snew(d->atom, 1);
363         *(d->atom) = *(s->atom);
364     }
365     else
366     {
367         d->atom = NULL;
368     }
369     for (i = 0; i < 4; i++)
370     {
371         d->a[i] = safe_strdup(s->a[i]);
372     }
373     copy_rvec(s->newx, d->newx);
374 }
375
376 void merge_hacks_lo(int ns, t_hack *s, int *nd, t_hack **d)
377 {
378     int i;
379
380     if (ns)
381     {
382         srenew(*d, *nd + ns);
383         for (i = 0; i < ns; i++)
384         {
385             copy_t_hack(&s[i], &(*d)[*nd + i]);
386         }
387         (*nd) += ns;
388     }
389 }
390
391 void merge_hacks(t_hackblock *s, t_hackblock *d)
392 {
393     merge_hacks_lo(s->nhack, s->hack, &d->nhack, &d->hack);
394 }
395
396 void merge_t_hackblock(t_hackblock *s, t_hackblock *d)
397 {
398     merge_hacks(s, d);
399     merge_t_bondeds(s->rb, d->rb, FALSE, FALSE);
400 }
401
402 void copy_t_hackblock(t_hackblock *s, t_hackblock *d)
403 {
404     int i;
405
406     *d       = *s;
407     d->name  = safe_strdup(s->name);
408     d->nhack = 0;
409     d->hack  = NULL;
410     for (i = 0; i < ebtsNR; i++)
411     {
412         d->rb[i].nb = 0;
413         d->rb[i].b  = NULL;
414     }
415     merge_t_hackblock(s, d);
416 }
417
418 #undef safe_strdup
419
420 void dump_hb(FILE *out, int nres, t_hackblock hb[])
421 {
422     int i, j, k, l;
423
424 #define SS(s) (s) ? (s) : "-"
425 #define SA(s) (s) ? "+" : ""
426     fprintf(out, "t_hackblock\n");
427     for (i = 0; i < nres; i++)
428     {
429         fprintf(out, "%3d %4s %2d %2d\n",
430                 i, SS(hb[i].name), hb[i].nhack, hb[i].maxhack);
431         if (hb[i].nhack)
432         {
433             for (j = 0; j < hb[i].nhack; j++)
434             {
435                 fprintf(out, "%d: %d %4s %4s %1s %2d %d %4s %4s %4s %4s\n",
436                         j, hb[i].hack[j].nr,
437                         SS(hb[i].hack[j].oname), SS(hb[i].hack[j].nname),
438                         SA(hb[i].hack[j].atom), hb[i].hack[j].tp, hb[i].hack[j].cgnr,
439                         SS(hb[i].hack[j].AI), SS(hb[i].hack[j].AJ),
440                         SS(hb[i].hack[j].AK), SS(hb[i].hack[j].AL) );
441             }
442         }
443         for (j = 0; j < ebtsNR; j++)
444         {
445             if (hb[i].rb[j].nb)
446             {
447                 fprintf(out, " %c %d:", btsNames[j][0], hb[i].rb[j].nb);
448                 for (k = 0; k < hb[i].rb[j].nb; k++)
449                 {
450                     fprintf(out, " [");
451                     for (l = 0; l < btsNiatoms[j]; l++)
452                     {
453                         fprintf(out, " %s", hb[i].rb[j].b[k].a[l]);
454                     }
455                     fprintf(out, " %s]", SS(hb[i].rb[j].b[k].s));
456                 }
457                 fprintf(out, " Entry matched: %s\n", yesno_names[hb[i].rb[j].b[k].match]);
458             }
459         }
460         fprintf(out, "\n");
461     }
462 #undef SS
463 #undef SA
464 }
465
466 void init_t_protonate(t_protonate *protonate)
467 {
468     protonate->bInit = FALSE;
469 }