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 * 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.
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.
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.
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.
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.
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.
38 /* This file is completely threadsafe - keep it that way! */
54 #include "gpp_nextnb.h"
57 #include "gmx_fatal.h"
62 #define DIHEDRAL_WAS_SET_IN_RTP 0
63 static gmx_bool was_dihedral_set_in_rtp(t_param *dih)
65 return dih->c[MAXFORCEPARAM-1] == DIHEDRAL_WAS_SET_IN_RTP;
68 typedef gmx_bool (*peq)(t_param *p1, t_param *p2);
70 static int acomp(const void *a1, const void *a2)
77 if ((ac=(p1->AJ-p2->AJ))!=0)
79 else if ((ac=(p1->AI-p2->AI))!=0)
82 return (p1->AK-p2->AK);
85 static int pcomp(const void *a1, const void *a2)
92 if ((pc=(p1->AI-p2->AI))!=0)
95 return (p1->AJ-p2->AJ);
98 static int dcomp(const void *d1, const void *d2)
105 /* First sort by J & K (the two central) atoms */
106 if ((dc=(p1->AJ-p2->AJ))!=0)
110 else if ((dc=(p1->AK-p2->AK))!=0)
114 /* Then make sure to put rtp dihedrals before generated ones */
115 else if (was_dihedral_set_in_rtp(p1) &&
116 !was_dihedral_set_in_rtp(p2))
120 else if (!was_dihedral_set_in_rtp(p1) &&
121 was_dihedral_set_in_rtp(p2))
125 /* Finally, sort by I and J (two outer) atoms */
126 else if ((dc=(p1->AI-p2->AI))!=0)
132 return (p1->AL-p2->AL);
137 static gmx_bool is_dihedral_on_same_bond(t_param *p1, t_param *p2)
139 if (((p1->AJ==p2->AJ) && (p1->AK==p2->AK)) ||
140 ((p1->AJ==p2->AK) && (p1->AK==p2->AJ)))
147 static gmx_bool preq(t_param *p1, t_param *p2)
149 if ((p1->AI==p2->AI) && (p1->AJ==p2->AJ))
155 static void rm2par(t_param p[], int *np, peq eq)
166 for(i=1; (i<(*np)); i++)
167 if (!eq(&p[i],&p[i-1]))
169 /* Index now holds pointers to all the non-equal params,
170 * this only works when p is sorted of course
172 for(i=0; (i<nind); i++) {
173 for(j=0; (j<MAXATOMLIST); j++)
174 p[i].a[j]=p[index[i]].a[j];
175 for(j=0; (j<MAXFORCEPARAM); j++)
176 p[i].c[j]=p[index[i]].c[j];
177 if (p[index[i]].a[0] == p[index[i]].a[1]) {
180 "Something VERY strange is going on in rm2par (gen_ad.c)\n"
181 "a[0] %u a[1] %u a[2] %u a[3] %u\n",
182 p[i].a[0],p[i].a[1],p[i].a[2],p[i].a[3]);
184 } else if (index[i] > i) {
185 /* Copy the string only if it comes from somewhere else
186 * otherwise we will end up copying a random (newly freed) pointer.
187 * Since the index is sorted we only have to test for index[i] > i.
189 strcpy(p[i].s,p[index[i]].s);
197 static void cppar(t_param p[], int np, t_params plist[], int ftype)
208 for(i=0; (i<np); i++) {
209 for(j=0; (j<nral); j++)
210 ps->param[ps->nr].a[j] = p[i].a[j];
211 for(j=0; (j<nrfp); j++)
212 ps->param[ps->nr].c[j] = p[i].c[j];
213 for(j=0; (j<MAXSLEN); j++)
214 ps->param[ps->nr].s[j] = p[i].s[j];
219 static void cpparam(t_param *dest, t_param *src)
223 for(j=0; (j<MAXATOMLIST); j++)
224 dest->a[j] = src->a[j];
225 for(j=0; (j<MAXFORCEPARAM); j++)
226 dest->c[j] = src->c[j];
227 for(j=0; (j<MAXSLEN); j++)
228 dest->s[j] = src->s[j];
231 static void set_p(t_param *p, atom_id ai[4], real *c, char *s)
237 for(j=0; (j<MAXFORCEPARAM); j++)
246 static int int_comp(const void *a,const void *b)
248 return (*(int *)a) - (*(int *)b);
251 static int atom_id_comp(const void *a,const void *b)
253 return (*(atom_id *)a) - (*(atom_id *)b);
256 static int eq_imp(atom_id a1[],atom_id a2[])
261 for(j=0; (j<4); j++) {
265 qsort(b1,4,(size_t)sizeof(b1[0]),int_comp);
266 qsort(b2,4,(size_t)sizeof(b2[0]),int_comp);
275 static int idcomp(const void *a,const void *b)
282 if ((d=(pa->a[0]-pb->a[0])) != 0)
284 else if ((d=(pa->a[3]-pb->a[3])) != 0)
286 else if ((d=(pa->a[1]-pb->a[1])) != 0)
289 return (int) (pa->a[2]-pb->a[2]);
292 static void sort_id(int nr,t_param ps[])
296 /* First swap order of atoms around if necessary */
297 for(i=0; (i<nr); i++) {
298 if (ps[i].a[3] < ps[i].a[0]) {
299 tmp = ps[i].a[3]; ps[i].a[3] = ps[i].a[0]; ps[i].a[0] = tmp;
300 tmp = ps[i].a[2]; ps[i].a[2] = ps[i].a[1]; ps[i].a[1] = tmp;
305 qsort(ps,nr,(size_t)sizeof(ps[0]),idcomp);
308 static int n_hydro(atom_id a[],char ***atomname)
313 for(i=0; (i<4); i+=3) {
314 aname=*atomname[a[i]];
315 c0=toupper(aname[0]);
318 else if (((int)strlen(aname) > 1) && (c0 >= '0') && (c0 <= '9')) {
319 c1=toupper(aname[1]);
327 /* Clean up the dihedrals (both generated and read from the .rtp
329 static void clean_dih(t_param *dih, int *ndih,t_param improper[],int nimproper,
330 t_atoms *atoms,gmx_bool bKeepAllGeneratedDihedrals,
331 gmx_bool bRemoveDihedralIfWithImproper)
336 /* Construct the list of the indices of the dihedrals
337 * (i.e. generated or read) that might be kept. */
338 snew(index, *ndih+1);
339 if (bKeepAllGeneratedDihedrals)
341 fprintf(stderr,"Keeping all generated dihedrals\n");
343 for(i = 0; i < nind; i++)
352 /* Check if generated dihedral i should be removed. The
353 * dihedrals have been sorted by dcomp() above, so all those
354 * on the same two central atoms are together, with those from
355 * the .rtp file preceding those that were automatically
356 * generated. We remove the latter if the former exist. */
357 for(i = 0; i < *ndih; i++)
359 /* Keep the dihedrals that were defined in the .rtp file,
360 * and the dihedrals that were generated and different
361 * from the last one (whether it was generated or not). */
362 if (was_dihedral_set_in_rtp(&dih[i]) ||
364 !is_dihedral_on_same_bond(&dih[i],&dih[i-1]))
373 for(i=0; i<nind; i++)
375 gmx_bool bWasSetInRTP = was_dihedral_set_in_rtp(&dih[index[i]]);
376 gmx_bool bKeep = TRUE;
377 if (!bWasSetInRTP && bRemoveDihedralIfWithImproper)
379 /* Remove the dihedral if there is an improper on the same
381 for(j = 0; j < nimproper && bKeep; j++)
383 bKeep = !is_dihedral_on_same_bond(&dih[index[i]],&improper[j]);
389 /* If we don't want all dihedrals, we want to select the
390 * ones with the fewest hydrogens. Note that any generated
391 * dihedrals on the same bond as an .rtp dihedral may have
392 * been already pruned above in the construction of
393 * index[]. However, their parameters are still present,
394 * and l is looping over this dihedral and all of its
395 * pruned siblings. */
396 int bestl = index[i];
397 if (!bKeepAllGeneratedDihedrals && !bWasSetInRTP)
399 /* Minimum number of hydrogens for i and l atoms */
403 is_dihedral_on_same_bond(&dih[index[i]],&dih[l]));
406 int nh = n_hydro(dih[l].a,atoms->atomname);
420 cpparam(&dih[k],&dih[bestl]);
426 for (i = k; i < *ndih; i++)
435 static int get_impropers(t_atoms *atoms,t_hackblock hb[],t_param **improper,
436 gmx_bool bAllowMissing)
439 t_rbondeds *impropers;
440 t_rbonded *hbimproper;
441 int nimproper,i,j,k,r,start,ninc,nalloc;
442 atom_id ai[MAXATOMLIST];
447 snew(*improper,nalloc);
449 /* Add all the impropers from the residue database to the list. */
453 for(i=0; (i<atoms->nres); i++) {
454 impropers=&hb[i].rb[ebtsIDIHS];
455 for(j=0; (j<impropers->nb); j++) {
457 for(k=0; (k<4) && !bStop; k++) {
458 ai[k] = search_atom(impropers->b[j].a[k],start,
460 "improper",bAllowMissing);
461 if (ai[k] == NO_ATID)
465 if (nimproper == nalloc) {
467 srenew(*improper,nalloc);
470 set_p(&((*improper)[nimproper]),ai,NULL,impropers->b[j].s);
474 while ((start<atoms->nr) && (atoms->atom[start].resind == i))
482 static int nb_dist(t_nextnb *nnb,int ai,int aj)
492 nrexcl=nnb->nrexcl[ai];
493 for(nre=1; (nre < nnb->nrex); nre++) {
495 for(nrx=0; (nrx < nrexcl[nre]); nrx++) {
496 if ((aj == a[nrx]) && (NRE == -1))
503 gmx_bool is_hydro(t_atoms *atoms,int ai)
505 return ((*(atoms->atomname[ai]))[0] == 'H');
508 static void get_atomnames_min(int n,char **anm,
509 int resind,t_atoms *atoms,atom_id *a)
513 /* Assume ascending residue numbering */
515 if (atoms->atom[a[m]].resind < resind)
517 else if (atoms->atom[a[m]].resind > resind)
521 strcat(anm[m],*(atoms->atomname[a[m]]));
525 static void gen_excls(t_atoms *atoms, t_excls *excls, t_hackblock hb[],
526 gmx_bool bAllowMissing)
529 atom_id a,astart,i1,i2,itmp;
535 for(a=0; a<atoms->nr; a++) {
536 r = atoms->atom[a].resind;
537 if (a==atoms->nr-1 || atoms->atom[a+1].resind != r) {
538 hbexcl = &hb[r].rb[ebtsEXCLS];
540 for(e=0; e<hbexcl->nb; e++) {
541 anm = hbexcl->b[e].a[0];
542 i1 = search_atom(anm,astart,atoms,
543 "exclusion",bAllowMissing);
544 anm = hbexcl->b[e].a[1];
545 i2 = search_atom(anm,astart,atoms,
546 "exclusion",bAllowMissing);
547 if (i1!=NO_ATID && i2!=NO_ATID) {
553 srenew(excls[i1].e,excls[i1].nr+1);
554 excls[i1].e[excls[i1].nr] = i2;
563 for(a=0; a<atoms->nr; a++)
565 qsort(excls[a].e,excls[a].nr,(size_t)sizeof(atom_id),atom_id_comp);
568 static void remove_excl(t_excls *excls, int remove)
572 for(i=remove+1; i<excls->nr; i++)
573 excls->e[i-1] = excls->e[i];
578 void clean_excls(t_nextnb *nnb, int nrexcl, t_excls excls[])
580 int i,j,j1,k,k1,l,l1,m,n,e;
584 /* extract all i-j-k-l neighbours from nnb struct */
585 for(i=0; (i<nnb->nr); i++) {
586 /* For all particles */
589 for(j=0; (j<nnb->nrexcl[i][1]); j++) {
590 /* For all first neighbours */
593 for(e=0; e<excl->nr; e++)
594 if (excl->e[e] == j1)
598 for(k=0; (k<nnb->nrexcl[j1][1]); k++) {
599 /* For all first neighbours of j1 */
602 for(e=0; e<excl->nr; e++)
603 if (excl->e[e] == k1)
607 for(l=0; (l<nnb->nrexcl[k1][1]); l++) {
608 /* For all first neighbours of k1 */
611 for(e=0; e<excl->nr; e++)
612 if (excl->e[e] == l1)
620 void generate_excls(t_nextnb *nnb, int nrexcl, t_excls excls[])
622 int i,j,j1,k,k1,l,l1,m,n,e,N;
625 for(N=1; (N<min(nrexcl,nnb->nrex)); N++) {
626 /* extract all i-j-k-l neighbours from nnb struct */
627 for(i=0; (i<nnb->nr); i++) {
628 /* For all particles */
631 excl->nr += nnb->nrexcl[i][N];
632 srenew(excl->e,excl->nr);
633 for(j=0; (j<nnb->nrexcl[i][N]); j++)
634 /* For all first neighbours */
635 if (nnb->a[i][N][j] != i)
636 excl->e[n++] = nnb->a[i][N][j];
641 /* Generate pairs, angles and dihedrals from .rtp settings */
642 void gen_pad(t_nextnb *nnb, t_atoms *atoms, t_restp rtp[],
643 t_params plist[], t_excls excls[], t_hackblock hb[],
644 gmx_bool bAllowMissing)
646 t_param *ang,*dih,*pai,*improper;
647 t_rbondeds *hbang, *hbdih;
649 int res,minres,maxres;
650 int i,j,j1,k,k1,l,l1,m,n,i1,i2;
651 int ninc,maxang,maxdih,maxpai;
652 int nang,ndih,npai,nimproper,nbd;
654 gmx_bool bFound,bExcl;
657 /* These are the angles, dihedrals and pairs that we generate
658 * from the bonds. The ones that are already there from the rtp file
665 maxang = maxdih = maxpai = ninc;
675 gen_excls(atoms,excls,hb,bAllowMissing);
677 /* Extract all i-j-k-l neighbours from nnb struct to generate all
678 * angles and dihedrals. */
679 for(i=0; (i<nnb->nr); i++)
680 /* For all particles */
681 for(j=0; (j<nnb->nrexcl[i][1]); j++) {
682 /* For all first neighbours */
684 for(k=0; (k<nnb->nrexcl[j1][1]); k++) {
685 /* For all first neighbours of j1 */
688 /* Generate every angle only once */
690 if (nang == maxang) {
699 set_p_string(&(ang[nang]),"");
701 minres = atoms->atom[ang[nang].a[0]].resind;
704 minres = min(minres,atoms->atom[ang[nang].a[m]].resind);
705 maxres = max(maxres,atoms->atom[ang[nang].a[m]].resind);
707 res = 2*minres-maxres;
709 res += maxres-minres;
710 get_atomnames_min(3,anm,res,atoms,ang[nang].a);
711 hbang=&hb[res].rb[ebtsANGLES];
712 for(l=0; (l<hbang->nb); l++) {
713 if (strcmp(anm[1],hbang->b[l].AJ)==0) {
717 ((strcmp(anm[m],hbang->b[l].AI)==0) &&
718 (strcmp(anm[2-m],hbang->b[l].AK)==0)));
720 set_p_string(&(ang[nang]),hbang->b[l].s);
724 } while (res < maxres);
728 /* Generate every dihedral, 1-4 exclusion and 1-4 interaction
731 for(l=0; (l<nnb->nrexcl[k1][1]); l++) {
732 /* For all first neighbours of k1 */
734 if ((l1 != i) && (l1 != j1)) {
735 if (ndih == maxdih) {
743 for (m=0; m<MAXFORCEPARAM; m++)
744 dih[ndih].c[m]=NOTSET;
745 set_p_string(&(dih[ndih]),"");
748 minres = atoms->atom[dih[ndih].a[0]].resind;
751 minres = min(minres,atoms->atom[dih[ndih].a[m]].resind);
752 maxres = max(maxres,atoms->atom[dih[ndih].a[m]].resind);
754 res = 2*minres-maxres;
756 res += maxres-minres;
757 get_atomnames_min(4,anm,res,atoms,dih[ndih].a);
758 hbdih=&hb[res].rb[ebtsPDIHS];
759 for(n=0; (n<hbdih->nb); n++) {
763 ((strcmp(anm[3*m], hbdih->b[n].AI)==0) &&
764 (strcmp(anm[1+m], hbdih->b[n].AJ)==0) &&
765 (strcmp(anm[2-m], hbdih->b[n].AK)==0) &&
766 (strcmp(anm[3-3*m],hbdih->b[n].AL)==0)));
768 set_p_string(&dih[ndih],hbdih->b[n].s);
770 /* Set the last parameter to be able to see
771 if the dihedral was in the rtp list.
773 dih[ndih].c[MAXFORCEPARAM-1] = DIHEDRAL_WAS_SET_IN_RTP;
776 /* Set the next direct in case the rtp contains
777 multiple entries for this dihedral.
779 if (ndih == maxdih) {
787 for (m=0; m<MAXFORCEPARAM; m++)
788 dih[ndih].c[m]=NOTSET;
791 } while (res < maxres);
794 if (ndih == maxdih) {
802 for (m=0; m<MAXFORCEPARAM; m++)
803 dih[ndih].c[m]=NOTSET;
804 set_p_string(&(dih[ndih]),"");
808 nbd=nb_dist(nnb,i,l1);
810 fprintf(debug,"Distance (%d-%d) = %d\n",i+1,l1+1,nbd);
815 for(m=0; m<excls[i1].nr; m++)
816 bExcl = bExcl || excls[i1].e[m]==i2;
818 if (rtp[0].bGenerateHH14Interactions ||
819 !(is_hydro(atoms,i1) && is_hydro(atoms,i2))) {
820 if (npai == maxpai) {
828 set_p_string(&(pai[npai]),"");
840 /* Sort angles with respect to j-i-k (middle atom first) */
842 qsort(ang,nang,(size_t)sizeof(ang[0]),acomp);
844 /* Sort dihedrals with respect to j-k-i-l (middle atoms first) */
846 qsort(dih,ndih,(size_t)sizeof(dih[0]),dcomp);
850 qsort(pai,npai,(size_t)sizeof(pai[0]),pcomp);
852 /* Remove doubles, could occur in 6-rings, such as phenyls,
853 maybe one does not want this when fudgeQQ < 1.
855 fprintf(stderr,"Before cleaning: %d pairs\n",npai);
856 rm2par(pai,&npai,preq);
859 /* Get the impropers from the database */
860 nimproper = get_impropers(atoms,hb,&improper,bAllowMissing);
862 /* Sort the impropers */
863 sort_id(nimproper,improper);
866 fprintf(stderr,"Before cleaning: %d dihedrals\n",ndih);
867 clean_dih(dih,&ndih,improper,nimproper,atoms,
868 rtp[0].bKeepAllGeneratedDihedrals,
869 rtp[0].bRemoveDihedralIfWithImproper);
872 /* Now we have unique lists of angles and dihedrals
873 * Copy them into the destination struct
875 cppar(ang, nang, plist,F_ANGLES);
876 cppar(dih, ndih, plist,F_PDIHS);
877 cppar(improper,nimproper,plist,F_IDIHS);
878 cppar(pai, npai, plist,F_LJ14);
880 /* Remove all exclusions which are within nrexcl */
881 clean_excls(nnb,rtp[0].nrexcl,excls);