2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, 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.
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.
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.
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.
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.
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.
37 /* This file is completely threadsafe - keep it that way! */
50 #include "gromacs/fileio/confio.h"
51 #include "gromacs/gmxpreprocess/gpp_nextnb.h"
52 #include "gromacs/gmxpreprocess/grompp_impl.h"
53 #include "gromacs/gmxpreprocess/notset.h"
54 #include "gromacs/gmxpreprocess/pgutil.h"
55 #include "gromacs/gmxpreprocess/topio.h"
56 #include "gromacs/gmxpreprocess/toputil.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/topology/ifunc.h"
59 #include "gromacs/utility/cstringutil.h"
60 #include "gromacs/utility/fatalerror.h"
61 #include "gromacs/utility/smalloc.h"
63 #include "hackblock.h"
66 #define DIHEDRAL_WAS_SET_IN_RTP 0
67 static bool was_dihedral_set_in_rtp(const InteractionOfType
&dih
)
69 // This is a bad way to check this, but I don't know how to make this better now.
70 gmx::ArrayRef
<const real
> forceParam
= dih
.forceParam();
71 return forceParam
[MAXFORCEPARAM
-1] == DIHEDRAL_WAS_SET_IN_RTP
;
74 typedef bool (*peq
)(const InteractionOfType
&p1
, const InteractionOfType
&p2
);
76 static bool acomp(const InteractionOfType
&a1
, const InteractionOfType
&a2
)
80 if ((ac
= (a1
.aj()-a2
.aj())) != 0)
84 else if ((ac
= (a1
.ai()-a2
.ai())) != 0)
90 return (a1
.ak() < a2
.ak());
94 static bool pcomp(const InteractionOfType
&a1
, const InteractionOfType
&a2
)
98 if ((pc
= (a1
.ai()-a2
.ai())) != 0)
104 return (a1
.aj() < a2
.aj());
108 static bool dcomp(const InteractionOfType
&d1
, const InteractionOfType
&d2
)
112 /* First sort by J & K (the two central) atoms */
113 if ((dc
= (d1
.aj()-d2
.aj())) != 0)
117 else if ((dc
= (d1
.ak()-d2
.ak())) != 0)
121 /* Then make sure to put rtp dihedrals before generated ones */
122 else if (was_dihedral_set_in_rtp(d1
) &&
123 !was_dihedral_set_in_rtp(d2
))
127 else if (!was_dihedral_set_in_rtp(d1
) &&
128 was_dihedral_set_in_rtp(d2
))
132 /* Then sort by I and J (two outer) atoms */
133 else if ((dc
= (d1
.ai()-d2
.ai())) != 0)
137 else if ((dc
= (d1
.al()-d2
.al())) != 0)
143 // AMBER force fields with type 9 dihedrals can reach here, where we sort on
144 // the contents of the string that names the macro for the parameters.
145 return std::lexicographical_compare(d1
.interactionTypeName().begin(),
146 d1
.interactionTypeName().end(),
147 d2
.interactionTypeName().begin(),
148 d2
.interactionTypeName().end());
153 static bool is_dihedral_on_same_bond(const InteractionOfType
&p1
, const InteractionOfType
&p2
)
155 return ((p1
.aj() == p2
.aj()) && (p1
.ak() == p2
.ak())) ||
156 ((p1
.aj() == p2
.ak()) && (p1
.ak() == p2
.aj()));
160 static bool preq(const InteractionOfType
&p1
, const InteractionOfType
&p2
)
162 return (p1
.ai() == p2
.ai()) && (p1
.aj() == p2
.aj());
165 static void rm2par(std::vector
<InteractionOfType
> *p
, peq eq
)
172 for (auto param
= p
->begin() + 1; param
!= p
->end(); )
174 auto prev
= param
- 1;
175 if (eq(*param
, *prev
))
177 param
= p
->erase(param
);
186 static void cppar(gmx::ArrayRef
<const InteractionOfType
> types
,
187 gmx::ArrayRef
<InteractionsOfType
> plist
,
191 for (const auto &type
: types
)
193 plist
[ftype
].interactionTypes
.push_back(type
);
197 static bool idcomp(const InteractionOfType
&a
, const InteractionOfType
&b
)
201 if ((d
= (a
.ai()-b
.ai())) != 0)
205 else if ((d
= (a
.al()-b
.al())) != 0)
209 else if ((d
= (a
.aj()-b
.aj())) != 0)
215 return (a
.ak() < b
.ak());
219 static void sort_id(gmx::ArrayRef
<InteractionOfType
> ps
)
223 for (auto &parm
: ps
)
227 std::sort(ps
.begin(), ps
.end(), idcomp
);
231 static int n_hydro(gmx::ArrayRef
<const int> a
, char ***atomname
)
235 for (auto atom
= a
.begin(); atom
< a
.end(); atom
+= 3)
237 const char *aname
= *atomname
[*atom
];
238 char c0
= toupper(aname
[0]);
243 else if ((static_cast<int>(strlen(aname
)) > 1) && (c0
>= '0') && (c0
<= '9'))
245 char c1
= toupper(aname
[1]);
255 /* Clean up the dihedrals (both generated and read from the .rtp
257 static std::vector
<InteractionOfType
> clean_dih(gmx::ArrayRef
<const InteractionOfType
> dih
,
258 gmx::ArrayRef
<const InteractionOfType
> improper
,
259 t_atoms
*atoms
, bool bKeepAllGeneratedDihedrals
,
260 bool bRemoveDihedralIfWithImproper
)
262 /* Construct the list of the indices of the dihedrals
263 * (i.e. generated or read) that might be kept. */
264 std::vector
< std::pair
< InteractionOfType
, int>> newDihedrals
;
265 if (bKeepAllGeneratedDihedrals
)
267 fprintf(stderr
, "Keeping all generated dihedrals\n");
269 for (const auto &dihedral
: dih
)
271 newDihedrals
.emplace_back(std::pair
<InteractionOfType
, int>(dihedral
, i
++));
276 /* Check if generated dihedral i should be removed. The
277 * dihedrals have been sorted by dcomp() above, so all those
278 * on the same two central atoms are together, with those from
279 * the .rtp file preceding those that were automatically
280 * generated. We remove the latter if the former exist. */
282 for (auto dihedral
= dih
.begin(); dihedral
!= dih
.end(); dihedral
++)
284 /* Keep the dihedrals that were defined in the .rtp file,
285 * and the dihedrals that were generated and different
286 * from the last one (whether it was generated or not). */
287 if (was_dihedral_set_in_rtp(*dihedral
) ||
288 dihedral
== dih
.begin() ||
289 !is_dihedral_on_same_bond(*dihedral
, *(dihedral
-1)))
291 newDihedrals
.emplace_back(std::pair
<InteractionOfType
, int>(*dihedral
, i
++));
296 for (auto dihedral
= newDihedrals
.begin(); dihedral
!= newDihedrals
.end(); )
298 bool bWasSetInRTP
= was_dihedral_set_in_rtp(dihedral
->first
);
300 if (!bWasSetInRTP
&& bRemoveDihedralIfWithImproper
)
302 /* Remove the dihedral if there is an improper on the same
304 for (auto imp
= improper
.begin(); imp
!= improper
.end() && bKeep
; ++imp
)
306 bKeep
= !is_dihedral_on_same_bond(dihedral
->first
, *imp
);
312 /* If we don't want all dihedrals, we want to select the
313 * ones with the fewest hydrogens. Note that any generated
314 * dihedrals on the same bond as an .rtp dihedral may have
315 * been already pruned above in the construction of
316 * index[]. However, their parameters are still present,
317 * and l is looping over this dihedral and all of its
318 * pruned siblings. */
319 int bestl
= dihedral
->second
;
320 if (!bKeepAllGeneratedDihedrals
&& !bWasSetInRTP
)
322 /* Minimum number of hydrogens for i and l atoms */
324 int next
= dihedral
->second
+ 1;
325 for (int l
= dihedral
->second
;
327 is_dihedral_on_same_bond(dihedral
->first
, dih
[l
]));
330 int nh
= n_hydro(dih
[l
].atoms(), atoms
->atomname
);
341 dihedral
->first
= dih
[bestl
];
351 dihedral
= newDihedrals
.erase(dihedral
);
354 std::vector
<InteractionOfType
> finalDihedrals
;
355 finalDihedrals
.reserve(newDihedrals
.size());
356 for (const auto ¶m
: newDihedrals
)
358 finalDihedrals
.emplace_back(param
.first
);
360 return finalDihedrals
;
363 static std::vector
<InteractionOfType
> get_impropers(t_atoms
*atoms
,
364 gmx::ArrayRef
<MoleculePatchDatabase
> globalPatches
,
367 std::vector
<InteractionOfType
> improper
;
369 /* Add all the impropers from the residue database to the list. */
371 if (!globalPatches
.empty())
373 for (int i
= 0; (i
< atoms
->nres
); i
++)
375 BondedInteractionList
*impropers
= &globalPatches
[i
].rb
[ebtsIDIHS
];
376 for (const auto &bondeds
: impropers
->b
)
380 for (int k
= 0; (k
< 4) && !bStop
; k
++)
382 int entry
= search_atom(bondeds
.a
[k
].c_str(), start
,
383 atoms
, "improper", bAllowMissing
);
387 ai
.emplace_back(entry
);
397 improper
.emplace_back(InteractionOfType(ai
, {}, bondeds
.s
));
400 while ((start
< atoms
->nr
) && (atoms
->atom
[start
].resind
== i
))
410 static int nb_dist(t_nextnb
*nnb
, int ai
, int aj
)
422 nrexcl
= nnb
->nrexcl
[ai
];
423 for (nre
= 1; (nre
< nnb
->nrex
); nre
++)
426 for (nrx
= 0; (nrx
< nrexcl
[nre
]); nrx
++)
428 if ((aj
== a
[nrx
]) && (NRE
== -1))
437 static bool is_hydro(t_atoms
*atoms
, int ai
)
439 return ((*(atoms
->atomname
[ai
]))[0] == 'H');
442 static void get_atomnames_min(int n
, gmx::ArrayRef
<std::string
> anm
,
443 int resind
, t_atoms
*atoms
, gmx::ArrayRef
<const int> a
)
445 /* Assume ascending residue numbering */
446 for (int m
= 0; m
< n
; m
++)
448 if (atoms
->atom
[a
[m
]].resind
< resind
)
452 else if (atoms
->atom
[a
[m
]].resind
> resind
)
460 anm
[m
].append(*(atoms
->atomname
[a
[m
]]));
464 static void gen_excls(t_atoms
*atoms
,
466 gmx::ArrayRef
<MoleculePatchDatabase
> globalPatches
,
470 for (int a
= 0; a
< atoms
->nr
; a
++)
472 int r
= atoms
->atom
[a
].resind
;
473 if (a
== atoms
->nr
-1 || atoms
->atom
[a
+1].resind
!= r
)
475 BondedInteractionList
*hbexcl
= &globalPatches
[r
].rb
[ebtsEXCLS
];
477 for (const auto &bondeds
: hbexcl
->b
)
479 const char *anm
= bondeds
.a
[0].c_str();
480 int i1
= search_atom(anm
, astart
, atoms
,
481 "exclusion", bAllowMissing
);
482 anm
= bondeds
.a
[1].c_str();
483 int i2
= search_atom(anm
, astart
, atoms
,
484 "exclusion", bAllowMissing
);
485 if (i1
!= -1 && i2
!= -1)
493 srenew(excls
[i1
].e
, excls
[i1
].nr
+1);
494 excls
[i1
].e
[excls
[i1
].nr
] = i2
;
503 for (int a
= 0; a
< atoms
->nr
; a
++)
507 std::sort(excls
[a
].e
, excls
[a
].e
+excls
[a
].nr
);
512 static void remove_excl(t_excls
*excls
, int remove
)
516 for (i
= remove
+1; i
< excls
->nr
; i
++)
518 excls
->e
[i
-1] = excls
->e
[i
];
524 void clean_excls(t_nextnb
*nnb
, int nrexcl
, t_excls excls
[])
526 int i
, j
, j1
, k
, k1
, l
, l1
, e
;
531 /* extract all i-j-k-l neighbours from nnb struct */
532 for (i
= 0; (i
< nnb
->nr
); i
++)
534 /* For all particles */
537 for (j
= 0; (j
< nnb
->nrexcl
[i
][1]); j
++)
539 /* For all first neighbours */
540 j1
= nnb
->a
[i
][1][j
];
542 for (e
= 0; e
< excl
->nr
; e
++)
544 if (excl
->e
[e
] == j1
)
546 remove_excl(excl
, e
);
552 for (k
= 0; (k
< nnb
->nrexcl
[j1
][1]); k
++)
554 /* For all first neighbours of j1 */
555 k1
= nnb
->a
[j1
][1][k
];
557 for (e
= 0; e
< excl
->nr
; e
++)
559 if (excl
->e
[e
] == k1
)
561 remove_excl(excl
, e
);
567 for (l
= 0; (l
< nnb
->nrexcl
[k1
][1]); l
++)
569 /* For all first neighbours of k1 */
570 l1
= nnb
->a
[k1
][1][l
];
572 for (e
= 0; e
< excl
->nr
; e
++)
574 if (excl
->e
[e
] == l1
)
576 remove_excl(excl
, e
);
588 void generate_excls(t_nextnb
*nnb
, int nrexcl
, t_excls excls
[])
593 for (N
= 1; (N
< std::min(nrexcl
, nnb
->nrex
)); N
++)
595 /* extract all i-j-k-l neighbours from nnb struct */
596 for (i
= 0; (i
< nnb
->nr
); i
++)
598 /* For all particles */
601 excl
->nr
+= nnb
->nrexcl
[i
][N
];
602 srenew(excl
->e
, excl
->nr
);
603 for (j
= 0; (j
< nnb
->nrexcl
[i
][N
]); j
++)
605 /* For all first neighbours */
606 if (nnb
->a
[i
][N
][j
] != i
)
608 excl
->e
[n
++] = nnb
->a
[i
][N
][j
];
615 /* Generate pairs, angles and dihedrals from .rtp settings */
616 void gen_pad(t_nextnb
*nnb
, t_atoms
*atoms
, gmx::ArrayRef
<const PreprocessResidue
> rtpFFDB
,
617 gmx::ArrayRef
<InteractionsOfType
> plist
, t_excls excls
[], gmx::ArrayRef
<MoleculePatchDatabase
> globalPatches
,
620 /* These are the angles, dihedrals and pairs that we generate
621 * from the bonds. The ones that are already there from the rtp file
624 std::vector
<InteractionOfType
> ang
;
625 std::vector
<InteractionOfType
> dih
;
626 std::vector
<InteractionOfType
> pai
;
627 std::vector
<InteractionOfType
> improper
;
629 std::array
<std::string
, 4> anm
;
631 if (!globalPatches
.empty())
633 gen_excls(atoms
, excls
, globalPatches
, bAllowMissing
);
634 /* mark all entries as not matched yet */
635 for (int i
= 0; i
< atoms
->nres
; i
++)
637 for (int j
= 0; j
< ebtsNR
; j
++)
639 for (auto &bondeds
: globalPatches
[i
].rb
[j
].b
)
641 bondeds
.match
= false;
647 /* Extract all i-j-k-l neighbours from nnb struct to generate all
648 * angles and dihedrals. */
649 for (int i
= 0; (i
< nnb
->nr
); i
++)
651 /* For all particles */
652 for (int j
= 0; (j
< nnb
->nrexcl
[i
][1]); j
++)
654 /* For all first neighbours */
655 int j1
= nnb
->a
[i
][1][j
];
656 for (int k
= 0; (k
< nnb
->nrexcl
[j1
][1]); k
++)
658 /* For all first neighbours of j1 */
659 int k1
= nnb
->a
[j1
][1][k
];
662 /* Generate every angle only once */
665 std::vector
<int> atomNumbers
= {i
, j1
, k1
};
667 if (!globalPatches
.empty())
669 int minres
= atoms
->atom
[i
].resind
;
671 for (int m
= 1; m
< 3; m
++)
673 minres
= std::min(minres
, atoms
->atom
[atomNumbers
[m
]].resind
);
674 maxres
= std::max(maxres
, atoms
->atom
[atomNumbers
[m
]].resind
);
676 int res
= 2*minres
-maxres
;
679 res
+= maxres
-minres
;
680 get_atomnames_min(3, anm
, res
, atoms
, atomNumbers
);
681 BondedInteractionList
*hbang
= &globalPatches
[res
].rb
[ebtsANGLES
];
682 for (auto &bondeds
: hbang
->b
)
684 if (anm
[1] == bondeds
.aj())
687 for (int m
= 0; m
< 3; m
+= 2)
690 ((anm
[m
] == bondeds
.ai()) &&
691 (anm
[2-m
] == bondeds
.ak())));
696 /* Mark that we found a match for this entry */
697 bondeds
.match
= true;
702 while (res
< maxres
);
704 ang
.push_back(InteractionOfType(atomNumbers
, {}, name
));
706 /* Generate every dihedral, 1-4 exclusion and 1-4 interaction
710 for (int l
= 0; (l
< nnb
->nrexcl
[k1
][1]); l
++)
712 /* For all first neighbours of k1 */
713 int l1
= nnb
->a
[k1
][1][l
];
714 if ((l1
!= i
) && (l1
!= j1
))
716 std::vector
<int> atomNumbers
= {i
, j1
, k1
, l1
};
719 if (!globalPatches
.empty())
721 int minres
= atoms
->atom
[i
].resind
;
723 for (int m
= 1; m
< 4; m
++)
727 atoms
->atom
[atomNumbers
[m
]].resind
);
730 atoms
->atom
[atomNumbers
[m
]].resind
);
732 int res
= 2*minres
-maxres
;
735 res
+= maxres
-minres
;
736 get_atomnames_min(4, anm
, res
, atoms
, atomNumbers
);
737 BondedInteractionList
*hbdih
= &globalPatches
[res
].rb
[ebtsPDIHS
];
738 for (auto &bondeds
: hbdih
->b
)
741 for (int m
= 0; m
< 2; m
++)
744 ((anm
[3*m
] == bondeds
.ai()) &&
745 (anm
[1+m
] == bondeds
.aj()) &&
746 (anm
[2-m
] == bondeds
.ak()) &&
747 (anm
[3-3*m
] == bondeds
.al())));
752 /* Mark that we found a match for this entry */
753 bondeds
.match
= true;
755 /* Set the last parameter to be able to see
756 if the dihedral was in the rtp list.
759 dih
.push_back(InteractionOfType(atomNumbers
, {}, name
));
760 dih
.back().setForceParameter(MAXFORCEPARAM
-1, DIHEDRAL_WAS_SET_IN_RTP
);
764 while (res
< maxres
);
768 std::vector
<int> atoms
= {i
, j1
, k1
, l1
};
769 dih
.push_back(InteractionOfType(atoms
, {}, ""));
772 int nbd
= nb_dist(nnb
, i
, l1
);
775 int i1
= std::min(i
, l1
);
776 int i2
= std::max(i
, l1
);
778 for (int m
= 0; m
< excls
[i1
].nr
; m
++)
780 bExcl
= bExcl
|| excls
[i1
].e
[m
] == i2
;
784 if (rtpFFDB
[0].bGenerateHH14Interactions
||
785 !(is_hydro(atoms
, i1
) && is_hydro(atoms
, i2
)))
787 std::vector
<int> atoms
= {i1
, i2
};
788 pai
.push_back(InteractionOfType(atoms
, {}, ""));
800 if (!globalPatches
.empty())
802 /* The above approach is great in that we double-check that e.g. an angle
803 * really corresponds to three atoms connected by bonds, but this is not
804 * generally true. Go through the angle and dihedral hackblocks to add
805 * entries that we have not yet marked as matched when going through bonds.
807 for (int i
= 0; i
< atoms
->nres
; i
++)
809 /* Add remaining angles from hackblock */
810 BondedInteractionList
*hbang
= &globalPatches
[i
].rb
[ebtsANGLES
];
811 for (auto &bondeds
: hbang
->b
)
815 /* We already used this entry, continue to the next */
818 /* Hm - entry not used, let's see if we can find all atoms */
819 std::vector
<int> atomNumbers
;
821 for (int k
= 0; k
< 3 && bFound
; k
++)
823 const char *p
= bondeds
.a
[k
].c_str();
830 else if (p
[0] == '+')
835 atomNumbers
.emplace_back(search_res_atom(p
, res
, atoms
, "angle", TRUE
));
836 bFound
= (atomNumbers
.back() != -1);
841 bondeds
.match
= true;
842 /* Incrementing nang means we save this angle */
843 ang
.push_back(InteractionOfType(atomNumbers
, {}, bondeds
.s
));
847 /* Add remaining dihedrals from hackblock */
848 BondedInteractionList
*hbdih
= &globalPatches
[i
].rb
[ebtsPDIHS
];
849 for (auto &bondeds
: hbdih
->b
)
853 /* We already used this entry, continue to the next */
856 /* Hm - entry not used, let's see if we can find all atoms */
857 std::vector
<int> atomNumbers
;
859 for (int k
= 0; k
< 4 && bFound
; k
++)
861 const char *p
= bondeds
.a
[k
].c_str();
868 else if (p
[0] == '+')
873 atomNumbers
.emplace_back(search_res_atom(p
, res
, atoms
, "dihedral", TRUE
));
874 bFound
= (atomNumbers
.back() != -1);
879 bondeds
.match
= true;
880 /* Incrementing ndih means we save this dihedral */
881 dih
.push_back(InteractionOfType(atomNumbers
, {}, bondeds
.s
));
887 /* Sort angles with respect to j-i-k (middle atom first) */
890 std::sort(ang
.begin(), ang
.end(), acomp
);
893 /* Sort dihedrals with respect to j-k-i-l (middle atoms first) */
896 std::sort(dih
.begin(), dih
.end(), dcomp
);
902 std::sort(pai
.begin(), pai
.end(), pcomp
);
906 /* Remove doubles, could occur in 6-rings, such as phenyls,
907 maybe one does not want this when fudgeQQ < 1.
909 fprintf(stderr
, "Before cleaning: %zu pairs\n", pai
.size());
913 /* Get the impropers from the database */
914 improper
= get_impropers(atoms
, globalPatches
, bAllowMissing
);
916 /* Sort the impropers */
921 fprintf(stderr
, "Before cleaning: %zu dihedrals\n", dih
.size());
922 dih
= clean_dih(dih
, improper
, atoms
,
923 rtpFFDB
[0].bKeepAllGeneratedDihedrals
,
924 rtpFFDB
[0].bRemoveDihedralIfWithImproper
);
927 /* Now we have unique lists of angles and dihedrals
928 * Copy them into the destination struct
930 cppar(ang
, plist
, F_ANGLES
);
931 cppar(dih
, plist
, F_PDIHS
);
932 cppar(improper
, plist
, F_IDIHS
);
933 cppar(pai
, plist
, F_LJ14
);
935 /* Remove all exclusions which are within nrexcl */
936 clean_excls(nnb
, rtpFFDB
[0].nrexcl
, excls
);