Merge gromacs-4-6 into master
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / vsite_parm.c
1 /*
2  * 
3  *                This source code is part of
4  * 
5  *                 G   R   O   M   A   C   S
6  * 
7  *          GROningen MAchine for Chemical Simulations
8  * 
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  * 
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <math.h>
41 #include <string.h>
42 #include "vsite_parm.h"
43 #include "smalloc.h"
44 #include "resall.h"
45 #include "add_par.h"
46 #include "vec.h"
47 #include "toputil.h"
48 #include "physics.h"
49 #include "index.h"
50 #include "names.h"
51 #include "gmx_fatal.h"
52 #include "string2.h"
53 #include "physics.h"
54
55 typedef struct {
56   t_iatom a[4];
57   real    c;
58 } t_mybonded;
59
60 typedef struct {
61   int     ftype;
62   t_param *param;
63 } vsitebondparam_t;
64
65 typedef struct {
66   int              nr;
67   int              ftype;
68   vsitebondparam_t *vsbp;
69 } at2vsitebond_t;
70
71 typedef struct {
72   int nr;
73   int *aj;
74 } at2vsitecon_t;
75
76 static int vsite_bond_nrcheck(int ftype)
77 {
78   int nrcheck;
79   
80   if ((interaction_function[ftype].flags & (IF_BTYPE | IF_CONSTRAINT | IF_ATYPE)) || (ftype == F_IDIHS))
81     nrcheck = NRAL(ftype);
82   else
83     nrcheck = 0;
84   
85   return nrcheck;
86 }
87
88 static void enter_bonded(int nratoms, int *nrbonded, t_mybonded **bondeds, 
89                          t_param *param)
90 {
91   int j;
92
93   srenew(*bondeds, *nrbonded+1);
94   
95   /* copy atom numbers */
96   for(j=0; j<nratoms; j++)
97     (*bondeds)[*nrbonded].a[j] = param->a[j];
98   /* copy parameter */
99   (*bondeds)[*nrbonded].c = param->C0;
100   
101   (*nrbonded)++;
102 }
103
104 static void get_bondeds(int nrat, t_iatom atoms[],
105                         at2vsitebond_t *at2vb, t_params plist[],
106                         int *nrbond, t_mybonded **bonds,
107                         int *nrang,  t_mybonded **angles,
108                         int *nridih, t_mybonded **idihs )
109 {
110   int     k,i,ftype,nrcheck;
111   t_param *param;
112   
113   for(k=0; k<nrat; k++) {
114     for(i=0; i<at2vb[atoms[k]].nr; i++) {
115       ftype = at2vb[atoms[k]].vsbp[i].ftype;
116       param = at2vb[atoms[k]].vsbp[i].param;
117       nrcheck = vsite_bond_nrcheck(ftype);
118       /* abuse nrcheck to see if we're adding bond, angle or idih */
119       switch (nrcheck) {
120       case 2: enter_bonded(nrcheck,nrbond,bonds, param); break;
121       case 3: enter_bonded(nrcheck,nrang, angles,param); break;
122       case 4: enter_bonded(nrcheck,nridih,idihs, param); break;
123       }
124     }
125   }
126 }
127
128 static at2vsitebond_t *make_at2vsitebond(int natoms,t_params plist[])
129 {
130   gmx_bool *bVSI;
131   int  ftype,i,j,nrcheck,nr;
132   t_iatom *aa;
133   at2vsitebond_t *at2vb;
134
135   snew(at2vb,natoms);
136
137   snew(bVSI,natoms);
138   for(ftype=0; (ftype<F_NRE); ftype++) {
139     if ((interaction_function[ftype].flags & IF_VSITE) && ftype != F_VSITEN) {
140       for(i=0; (i<plist[ftype].nr); i++) {
141         for(j=0; j<NRAL(ftype); j++)
142           bVSI[plist[ftype].param[i].a[j]] = TRUE;
143       }
144     }
145   }
146   
147   for(ftype=0; (ftype<F_NRE); ftype++) {
148     nrcheck = vsite_bond_nrcheck(ftype);
149     if (nrcheck > 0) {
150       for(i=0; (i<plist[ftype].nr); i++) {
151         aa = plist[ftype].param[i].a;
152         for(j=0; j<nrcheck; j++) {
153           if (bVSI[aa[j]]) {
154             nr = at2vb[aa[j]].nr;
155             if (nr % 10 == 0)
156               srenew(at2vb[aa[j]].vsbp,nr+10);
157             at2vb[aa[j]].vsbp[nr].ftype = ftype;
158             at2vb[aa[j]].vsbp[nr].param = &plist[ftype].param[i];
159             at2vb[aa[j]].nr++;
160           }
161         }
162       }
163     }
164   }
165   sfree(bVSI);
166
167   return at2vb;
168 }
169
170 static void done_at2vsitebond(int natoms,at2vsitebond_t *at2vb)
171 {
172   int i;
173
174   for(i=0; i<natoms; i++)
175     if (at2vb[i].nr)
176       sfree(at2vb[i].vsbp);
177   sfree(at2vb);
178 }
179
180 static at2vsitecon_t *make_at2vsitecon(int natoms,t_params plist[])
181 {
182   gmx_bool *bVSI;
183   int  ftype,i,j,ai,aj,nr;
184   at2vsitecon_t *at2vc;
185
186   snew(at2vc,natoms);
187
188   snew(bVSI,natoms);
189   for(ftype=0; (ftype<F_NRE); ftype++) {
190     if ((interaction_function[ftype].flags & IF_VSITE) && ftype != F_VSITEN) {
191       for(i=0; (i<plist[ftype].nr); i++) {
192         for(j=0; j<NRAL(ftype); j++)
193           bVSI[plist[ftype].param[i].a[j]] = TRUE;
194       }
195     }
196   }
197   
198   for(ftype=0; (ftype<F_NRE); ftype++) {
199     if (interaction_function[ftype].flags & IF_CONSTRAINT) {
200       for(i=0; (i<plist[ftype].nr); i++) {
201         ai = plist[ftype].param[i].AI;
202         aj = plist[ftype].param[i].AJ;
203         if (bVSI[ai] && bVSI[aj]) {
204           /* Store forward direction */
205           nr = at2vc[ai].nr;
206           if (nr % 10 == 0)
207             srenew(at2vc[ai].aj,nr+10);
208           at2vc[ai].aj[nr] = aj;
209           at2vc[ai].nr++;
210           /* Store backward direction */
211           nr = at2vc[aj].nr;
212           if (nr % 10 == 0)
213             srenew(at2vc[aj].aj,nr+10);
214           at2vc[aj].aj[nr] = ai;
215           at2vc[aj].nr++;
216         }
217       }
218     }
219   }
220   sfree(bVSI);
221
222   return at2vc;
223 }
224
225 static void done_at2vsitecon(int natoms,at2vsitecon_t *at2vc)
226 {
227   int i;
228
229   for(i=0; i<natoms; i++)
230     if (at2vc[i].nr)
231       sfree(at2vc[i].aj);
232   sfree(at2vc);
233 }
234
235 /* for debug */
236 static void print_bad(FILE *fp, 
237                       int nrbond, t_mybonded *bonds,
238                       int nrang,  t_mybonded *angles,
239                       int nridih, t_mybonded *idihs )
240 {
241   int i;
242   
243   if (nrbond) {
244     fprintf(fp,"bonds:");
245     for(i=0; i<nrbond; i++)
246       fprintf(fp," %u-%u (%g)", 
247               bonds[i].AI+1, bonds[i].AJ+1, bonds[i].c);
248     fprintf(fp,"\n");
249   }
250   if (nrang) {
251     fprintf(fp,"angles:");
252     for(i=0; i<nrang; i++)
253       fprintf(fp," %u-%u-%u (%g)", 
254               angles[i].AI+1, angles[i].AJ+1, 
255               angles[i].AK+1, angles[i].c);
256     fprintf(fp,"\n");
257   }
258   if (nridih) {
259     fprintf(fp,"idihs:");
260     for(i=0; i<nridih; i++)
261       fprintf(fp," %u-%u-%u-%u (%g)", 
262               idihs[i].AI+1, idihs[i].AJ+1, 
263               idihs[i].AK+1, idihs[i].AL+1, idihs[i].c);
264     fprintf(fp,"\n");
265   }
266 }
267
268 static void print_param(FILE *fp, int ftype, int i, t_param *param)
269 {
270   static int pass = 0;
271   static int prev_ftype= NOTSET;
272   static int prev_i    = NOTSET;
273   int j;
274   
275   if ( (ftype!=prev_ftype) || (i!=prev_i) ) {
276     pass = 0;
277     prev_ftype= ftype;
278     prev_i    = i;
279   }
280   fprintf(fp,"(%d) plist[%s].param[%d]",
281           pass,interaction_function[ftype].name,i);
282   for(j=0; j<NRFP(ftype); j++)
283     fprintf(fp,".c[%d]=%g ",j,param->c[j]);
284   fprintf(fp,"\n");
285   pass++;
286 }
287
288 static real get_bond_length(int nrbond, t_mybonded bonds[], 
289                             t_iatom ai, t_iatom aj)
290 {
291   int  i;
292   real bondlen;
293   
294   bondlen=NOTSET;
295   for (i=0; i < nrbond && (bondlen==NOTSET); i++) {
296     /* check both ways */
297     if ( ( (ai == bonds[i].AI) && (aj == bonds[i].AJ) ) || 
298          ( (ai == bonds[i].AJ) && (aj == bonds[i].AI) ) )
299       bondlen = bonds[i].c; /* note: bonds[i].c might be NOTSET */
300   }
301   return bondlen;
302 }
303
304 static real get_angle(int nrang, t_mybonded angles[], 
305                       t_iatom ai, t_iatom aj, t_iatom ak)
306 {
307   int  i;
308   real angle;
309   
310   angle=NOTSET;
311   for (i=0; i < nrang && (angle==NOTSET); i++) {
312     /* check both ways */
313     if ( ( (ai==angles[i].AI) && (aj==angles[i].AJ) && (ak==angles[i].AK) ) || 
314          ( (ai==angles[i].AK) && (aj==angles[i].AJ) && (ak==angles[i].AI) ) )
315       angle = DEG2RAD*angles[i].c;
316   }
317   return angle;
318 }
319
320 static char *get_atomtype_name_AB(t_atom *atom,gpp_atomtype_t atype)
321 {
322     char *name;
323
324     name = get_atomtype_name(atom->type,atype);
325
326     /* When using the decoupling option, atom types are changed
327      * to decoupled for the non-bonded interactions, but the virtual
328      * sites constructions should be based on the "normal" interactions.
329      * So we return the state B atom type name if the state A atom
330      * type is the decoupled one. We should actually check for the atom
331      * type number, but that's not passed here. So we check for
332      * the decoupled atom type name. This should not cause trouble
333      * as this code is only used for topologies with v-sites without
334      * parameters generated by pdb2gmx.
335      */
336     if (strcmp(name,"decoupled") == 0)
337     {
338         name = get_atomtype_name(atom->typeB,atype);
339     }
340
341     return name;
342 }
343
344 static gmx_bool calc_vsite3_param(gpp_atomtype_t atype,
345                               t_param *param, t_atoms *at,
346                               int nrbond, t_mybonded *bonds,
347                               int nrang,  t_mybonded *angles )
348 {
349   /* i = virtual site          |    ,k
350    * j = 1st bonded heavy atom | i-j
351    * k,l = 2nd bonded atoms    |    `l
352    */
353   
354   gmx_bool bXH3,bError;
355   real bjk,bjl,a=-1,b=-1;
356   /* check if this is part of a NH3 , NH2-umbrella or CH3 group,
357    * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
358   if (debug) {
359     int i;
360     for (i=0; i<4; i++)
361       fprintf(debug,"atom %u type %s ",
362               param->a[i]+1,
363               get_atomtype_name_AB(&at->atom[param->a[i]],atype));
364     fprintf(debug,"\n");
365   }
366   bXH3 = 
367     ( (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AK],atype),"MNH",3)==0) &&
368       (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AL],atype),"MNH",3)==0) ) ||
369     ( (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AK],atype),"MCH3",4)==0) &&
370       (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AL],atype),"MCH3",4)==0) );
371   
372   bjk = get_bond_length(nrbond, bonds, param->AJ, param->AK);
373   bjl = get_bond_length(nrbond, bonds, param->AJ, param->AL);
374   bError = (bjk==NOTSET) || (bjl==NOTSET);
375   if (bXH3) {
376     /* now we get some XH2/XH3 group specific construction */
377     /* note: we call the heavy atom 'C' and the X atom 'N' */
378     real bMM,bCM,bCN,bNH,aCNH,dH,rH,dM,rM;
379     int aN;
380     
381     /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
382     bError = bError || (bjk!=bjl);
383     
384     /* the X atom (C or N) in the XH2/XH3 group is the first after the masses: */
385     aN = max(param->AK,param->AL)+1;
386     
387     /* get common bonds */
388     bMM = get_bond_length(nrbond, bonds, param->AK, param->AL);
389     bCM = bjk;
390     bCN = get_bond_length(nrbond, bonds, param->AJ, aN);
391     bError = bError || (bMM==NOTSET) || (bCN==NOTSET);
392     
393     /* calculate common things */
394     rM  = 0.5*bMM;
395     dM  = sqrt( sqr(bCM) - sqr(rM) );
396     
397     /* are we dealing with the X atom? */
398     if ( param->AI == aN ) {
399       /* this is trivial */
400       a = b = 0.5 * bCN/dM;
401       
402     } else {
403       /* get other bondlengths and angles: */
404       bNH = get_bond_length(nrbond, bonds, aN, param->AI);
405       aCNH= get_angle      (nrang, angles, param->AJ, aN, param->AI);
406       bError = bError || (bNH==NOTSET) || (aCNH==NOTSET);
407       
408       /* calculate */
409       dH  = bCN - bNH * cos(aCNH);
410       rH  = bNH * sin(aCNH);
411       
412       a = 0.5 * ( dH/dM + rH/rM );
413       b = 0.5 * ( dH/dM - rH/rM );
414     }
415   } else
416     gmx_fatal(FARGS,"calc_vsite3_param not implemented for the general case "
417                 "(atom %d)",param->AI+1);
418   
419   param->C0 = a;
420   param->C1 = b;
421   
422   if (debug)
423     fprintf(debug,"params for vsite3 %u: %g %g\n",
424             param->AI+1,param->C0,param->C1);
425   
426   return bError;
427 }
428
429 static gmx_bool calc_vsite3fd_param(t_param *param,
430                                 int nrbond, t_mybonded *bonds,
431                                 int nrang,  t_mybonded *angles)
432 {
433   /* i = virtual site          |    ,k
434    * j = 1st bonded heavy atom | i-j
435    * k,l = 2nd bonded atoms    |    `l
436    */
437
438   gmx_bool bError;
439   real bij,bjk,bjl,aijk,aijl,rk,rl;
440   
441   bij = get_bond_length(nrbond, bonds, param->AI, param->AJ);
442   bjk = get_bond_length(nrbond, bonds, param->AJ, param->AK);
443   bjl = get_bond_length(nrbond, bonds, param->AJ, param->AL);
444   aijk= get_angle      (nrang, angles, param->AI, param->AJ, param->AK);
445   aijl= get_angle      (nrang, angles, param->AI, param->AJ, param->AL);
446   bError = (bij==NOTSET) || (bjk==NOTSET) || (bjl==NOTSET) || 
447     (aijk==NOTSET) || (aijl==NOTSET);
448   
449   rk = bjk * sin(aijk);
450   rl = bjl * sin(aijl);
451   param->C0 = rk / (rk + rl);
452   param->C1 = -bij; /* 'bond'-length for fixed distance vsite */
453   
454   if (debug)
455     fprintf(debug,"params for vsite3fd %u: %g %g\n",
456             param->AI+1,param->C0,param->C1);
457   return bError;
458 }
459
460 static gmx_bool calc_vsite3fad_param(t_param *param,
461                                  int nrbond, t_mybonded *bonds,
462                                  int nrang,  t_mybonded *angles)
463 {
464   /* i = virtual site          |
465    * j = 1st bonded heavy atom | i-j
466    * k = 2nd bonded heavy atom |    `k-l
467    * l = 3d bonded heavy atom  |
468    */
469
470   gmx_bool bSwapParity,bError;
471   real bij,aijk;
472   
473   bSwapParity = ( param->C1 == -1 );
474   
475   bij  = get_bond_length(nrbond, bonds, param->AI, param->AJ);
476   aijk = get_angle      (nrang, angles, param->AI, param->AJ, param->AK);
477   bError = (bij==NOTSET) || (aijk==NOTSET);
478   
479   param->C1 = bij;          /* 'bond'-length for fixed distance vsite */
480   param->C0 = RAD2DEG*aijk; /* 'bond'-angle for fixed angle vsite */
481   
482   if (bSwapParity)
483     param->C0 = 360 - param->C0;
484   
485   if (debug)
486     fprintf(debug,"params for vsite3fad %u: %g %g\n",
487             param->AI+1,param->C0,param->C1);
488   return bError;
489 }
490
491 static gmx_bool calc_vsite3out_param(gpp_atomtype_t atype,
492                                  t_param *param, t_atoms *at,
493                                  int nrbond, t_mybonded *bonds,
494                                  int nrang,  t_mybonded *angles)
495 {
496   /* i = virtual site          |    ,k
497    * j = 1st bonded heavy atom | i-j
498    * k,l = 2nd bonded atoms    |    `l
499    * NOTE: i is out of the j-k-l plane!
500    */
501   
502   gmx_bool bXH3,bError,bSwapParity;
503   real bij,bjk,bjl,aijk,aijl,akjl,pijk,pijl,a,b,c;
504   
505   /* check if this is part of a NH2-umbrella, NH3 or CH3 group,
506    * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
507   if (debug) {
508     int i;
509     for (i=0; i<4; i++)
510       fprintf(debug,"atom %u type %s ",
511               param->a[i]+1,get_atomtype_name_AB(&at->atom[param->a[i]],atype));
512     fprintf(debug,"\n");
513   }
514   bXH3 = 
515     ( (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AK],atype),"MNH",3)==0) &&
516       (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AL],atype),"MNH",3)==0) ) ||
517     ( (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AK],atype),"MCH3",4)==0) &&
518       (gmx_strncasecmp(get_atomtype_name_AB(&at->atom[param->AL],atype),"MCH3",4)==0) );
519   
520   /* check if construction parity must be swapped */  
521   bSwapParity = ( param->C1 == -1 );
522   
523   bjk = get_bond_length(nrbond, bonds, param->AJ, param->AK);
524   bjl = get_bond_length(nrbond, bonds, param->AJ, param->AL);
525   bError = (bjk==NOTSET) || (bjl==NOTSET);
526   if (bXH3) {
527     /* now we get some XH3 group specific construction */
528     /* note: we call the heavy atom 'C' and the X atom 'N' */
529     real bMM,bCM,bCN,bNH,aCNH,dH,rH,rHx,rHy,dM,rM;
530     int aN;
531     
532     /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
533     bError = bError || (bjk!=bjl);
534     
535     /* the X atom (C or N) in the XH3 group is the first after the masses: */
536     aN = max(param->AK,param->AL)+1;
537     
538     /* get all bondlengths and angles: */
539     bMM = get_bond_length(nrbond, bonds, param->AK, param->AL);
540     bCM = bjk;
541     bCN = get_bond_length(nrbond, bonds, param->AJ, aN);
542     bNH = get_bond_length(nrbond, bonds, aN, param->AI);
543     aCNH= get_angle      (nrang, angles, param->AJ, aN, param->AI);
544     bError = bError || 
545       (bMM==NOTSET) || (bCN==NOTSET) || (bNH==NOTSET) || (aCNH==NOTSET);
546     
547     /* calculate */
548     dH  = bCN - bNH * cos(aCNH);
549     rH  = bNH * sin(aCNH);
550     /* we assume the H's are symmetrically distributed */
551     rHx = rH*cos(DEG2RAD*30);
552     rHy = rH*sin(DEG2RAD*30);
553     rM  = 0.5*bMM;
554     dM  = sqrt( sqr(bCM) - sqr(rM) );
555     a   = 0.5*( (dH/dM) - (rHy/rM) );
556     b   = 0.5*( (dH/dM) + (rHy/rM) );
557     c   = rHx / (2*dM*rM);
558     
559   } else {
560     /* this is the general construction */
561     
562     bij = get_bond_length(nrbond, bonds, param->AI, param->AJ);
563     aijk= get_angle      (nrang, angles, param->AI, param->AJ, param->AK);
564     aijl= get_angle      (nrang, angles, param->AI, param->AJ, param->AL);
565     akjl= get_angle      (nrang, angles, param->AK, param->AJ, param->AL);
566     bError = bError || 
567       (bij==NOTSET) || (aijk==NOTSET) || (aijl==NOTSET) || (akjl==NOTSET);
568   
569     pijk = cos(aijk)*bij;
570     pijl = cos(aijl)*bij;
571     a = ( pijk + (pijk*cos(akjl)-pijl) * cos(akjl) / sqr(sin(akjl)) ) / bjk;
572     b = ( pijl + (pijl*cos(akjl)-pijk) * cos(akjl) / sqr(sin(akjl)) ) / bjl;
573     c = - sqrt( sqr(bij) - 
574                 ( sqr(pijk) - 2*pijk*pijl*cos(akjl) + sqr(pijl) ) 
575                 / sqr(sin(akjl)) )
576       / ( bjk*bjl*sin(akjl) );
577   }
578   
579   param->C0 = a;
580   param->C1 = b;
581   if (bSwapParity)
582     param->C2 = -c;
583   else
584     param->C2 =  c;
585   if (debug)
586     fprintf(debug,"params for vsite3out %u: %g %g %g\n",
587             param->AI+1,param->C0,param->C1,param->C2);
588   return bError;
589 }
590
591 static gmx_bool calc_vsite4fd_param(t_param *param,
592                                 int nrbond, t_mybonded *bonds,
593                                 int nrang,  t_mybonded *angles)
594 {
595   /* i = virtual site          |    ,k
596    * j = 1st bonded heavy atom | i-j-m
597    * k,l,m = 2nd bonded atoms  |    `l
598    */
599   
600   gmx_bool bError;
601   real bij,bjk,bjl,bjm,aijk,aijl,aijm,akjm,akjl;
602   real pk,pl,pm,cosakl,cosakm,sinakl,sinakm,cl,cm;
603   
604   bij = get_bond_length(nrbond, bonds, param->AI, param->AJ);
605   bjk = get_bond_length(nrbond, bonds, param->AJ, param->AK);
606   bjl = get_bond_length(nrbond, bonds, param->AJ, param->AL);
607   bjm = get_bond_length(nrbond, bonds, param->AJ, param->AM);
608   aijk= get_angle      (nrang, angles, param->AI, param->AJ, param->AK);
609   aijl= get_angle      (nrang, angles, param->AI, param->AJ, param->AL);
610   aijm= get_angle      (nrang, angles, param->AI, param->AJ, param->AM);
611   akjm= get_angle      (nrang, angles, param->AK, param->AJ, param->AM);
612   akjl= get_angle      (nrang, angles, param->AK, param->AJ, param->AL);
613   bError = (bij==NOTSET) || (bjk==NOTSET) || (bjl==NOTSET) || (bjm==NOTSET) ||
614     (aijk==NOTSET) || (aijl==NOTSET) || (aijm==NOTSET) || (akjm==NOTSET) || 
615     (akjl==NOTSET);
616   
617   if (!bError) {
618     pk = bjk*sin(aijk);
619     pl = bjl*sin(aijl);
620     pm = bjm*sin(aijm);
621     cosakl = (cos(akjl) - cos(aijk)*cos(aijl)) / (sin(aijk)*sin(aijl));
622     cosakm = (cos(akjm) - cos(aijk)*cos(aijm)) / (sin(aijk)*sin(aijm));
623     if ( cosakl < -1 || cosakl > 1 || cosakm < -1 || cosakm > 1 ) {
624       fprintf(stderr,"virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
625               param->AI+1,RAD2DEG*aijk,RAD2DEG*aijl,RAD2DEG*aijm);
626       gmx_fatal(FARGS,"invalid construction in calc_vsite4fd for atom %d: "
627                   "cosakl=%f, cosakm=%f\n",param->AI+1,cosakl,cosakm);
628     }
629     sinakl = sqrt(1-sqr(cosakl));
630     sinakm = sqrt(1-sqr(cosakm));
631     
632     /* note: there is a '+' because of the way the sines are calculated */
633     cl = -pk / ( pl*cosakl - pk + pl*sinakl*(pm*cosakm-pk)/(pm*sinakm) );
634     cm = -pk / ( pm*cosakm - pk + pm*sinakm*(pl*cosakl-pk)/(pl*sinakl) );
635     
636     param->C0 = cl;
637     param->C1 = cm;
638     param->C2 = -bij;
639     if (debug)
640       fprintf(debug,"params for vsite4fd %u: %g %g %g\n",
641               param->AI+1,param->C0,param->C1,param->C2);
642   }
643   
644   return bError;
645 }
646
647
648 static gmx_bool 
649 calc_vsite4fdn_param(t_param *param,
650                      int nrbond, t_mybonded *bonds,
651                      int nrang,  t_mybonded *angles)
652 {
653     /* i = virtual site          |    ,k
654     * j = 1st bonded heavy atom | i-j-m
655     * k,l,m = 2nd bonded atoms  |    `l
656     */
657     
658     gmx_bool bError;
659     real bij,bjk,bjl,bjm,aijk,aijl,aijm;
660     real pk,pl,pm,a,b;
661     
662     bij = get_bond_length(nrbond, bonds, param->AI, param->AJ);
663     bjk = get_bond_length(nrbond, bonds, param->AJ, param->AK);
664     bjl = get_bond_length(nrbond, bonds, param->AJ, param->AL);
665     bjm = get_bond_length(nrbond, bonds, param->AJ, param->AM);
666     aijk= get_angle      (nrang, angles, param->AI, param->AJ, param->AK);
667     aijl= get_angle      (nrang, angles, param->AI, param->AJ, param->AL);
668     aijm= get_angle      (nrang, angles, param->AI, param->AJ, param->AM);
669
670     bError = (bij==NOTSET) || (bjk==NOTSET) || (bjl==NOTSET) || (bjm==NOTSET) ||
671         (aijk==NOTSET) || (aijl==NOTSET) || (aijm==NOTSET);
672     
673     if (!bError) {
674         
675         /* Calculate component of bond j-k along the direction i-j */
676         pk = -bjk*cos(aijk);
677
678         /* Calculate component of bond j-l along the direction i-j */
679         pl = -bjl*cos(aijl);
680
681         /* Calculate component of bond j-m along the direction i-j */
682         pm = -bjm*cos(aijm);
683         
684         if(fabs(pl)<1000*GMX_REAL_MIN || fabs(pm)<1000*GMX_REAL_MIN)
685         {
686             fprintf(stderr,"virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
687                     param->AI+1,RAD2DEG*aijk,RAD2DEG*aijl,RAD2DEG*aijm);
688             gmx_fatal(FARGS,"invalid construction in calc_vsite4fdn for atom %d: "
689                       "pl=%f, pm=%f\n",param->AI+1,pl,pm);
690         }
691         
692         a = pk/pl;
693         b = pk/pm;
694           
695         param->C0 = a;
696         param->C1 = b;
697         param->C2 = bij;
698         
699         if (debug)
700             fprintf(debug,"params for vsite4fdn %u: %g %g %g\n",
701                     param->AI+1,param->C0,param->C1,param->C2);
702     }
703     
704     return bError;
705 }
706
707
708
709 int set_vsites(gmx_bool bVerbose, t_atoms *atoms, gpp_atomtype_t atype,
710                 t_params plist[])
711 {
712   int i,j,ftype;
713   int nvsite,nrbond,nrang,nridih,nrset;
714   gmx_bool bFirst,bSet,bERROR;
715   at2vsitebond_t *at2vb;
716   t_mybonded *bonds;
717   t_mybonded *angles;
718   t_mybonded *idihs;
719   
720   bFirst = TRUE;
721   bERROR = TRUE;
722   nvsite=0;
723   if (debug)
724     fprintf(debug, "\nCalculating parameters for virtual sites\n");
725
726   /* Make a reverse list to avoid ninteractions^2 operations */
727   at2vb = make_at2vsitebond(atoms->nr,plist);
728
729   for(ftype=0; (ftype<F_NRE); ftype++)
730     if ((interaction_function[ftype].flags & IF_VSITE) && ftype != F_VSITEN) {
731       nrset=0;
732       nvsite+=plist[ftype].nr;
733       for(i=0; (i<plist[ftype].nr); i++) {
734         /* check if all parameters are set */
735         bSet=TRUE;
736         for(j=0; j<NRFP(ftype) && bSet; j++)
737           bSet = plist[ftype].param[i].c[j]!=NOTSET;
738
739         if (debug) {
740           fprintf(debug,"bSet=%s ",bool_names[bSet]);
741           print_param(debug,ftype,i,&plist[ftype].param[i]);
742         }
743         if (!bSet) {
744           if (bVerbose && bFirst) {
745             fprintf(stderr,"Calculating parameters for virtual sites\n");
746             bFirst=FALSE;
747           }
748           
749           nrbond=nrang=nridih=0;
750           bonds = NULL;
751           angles= NULL;
752           idihs = NULL;
753           nrset++;
754           /* now set the vsite parameters: */
755           get_bondeds(NRAL(ftype), plist[ftype].param[i].a, at2vb, plist, 
756                       &nrbond, &bonds, &nrang,  &angles, &nridih, &idihs);
757           if (debug) {
758             fprintf(debug, "Found %d bonds, %d angles and %d idihs "
759                     "for virtual site %u (%s)\n",nrbond,nrang,nridih,
760                     plist[ftype].param[i].AI+1,
761                     interaction_function[ftype].longname);
762             print_bad(debug, nrbond, bonds, nrang, angles, nridih, idihs);
763           } /* debug */
764           switch(ftype) {
765           case F_VSITE3: 
766             bERROR = 
767               calc_vsite3_param(atype, &(plist[ftype].param[i]), atoms,
768                                 nrbond, bonds, nrang, angles);
769             break;
770           case F_VSITE3FD:
771             bERROR = 
772               calc_vsite3fd_param(&(plist[ftype].param[i]),
773                                   nrbond, bonds, nrang, angles);
774             break;
775           case F_VSITE3FAD:
776             bERROR = 
777               calc_vsite3fad_param(&(plist[ftype].param[i]),
778                                    nrbond, bonds, nrang, angles);
779             break;
780           case F_VSITE3OUT:
781             bERROR = 
782               calc_vsite3out_param(atype, &(plist[ftype].param[i]), atoms,
783                                    nrbond, bonds, nrang, angles);
784             break;
785           case F_VSITE4FD:
786             bERROR = 
787               calc_vsite4fd_param(&(plist[ftype].param[i]), 
788                                   nrbond, bonds, nrang, angles);
789             break;
790           case F_VSITE4FDN:
791           bERROR = 
792               calc_vsite4fdn_param(&(plist[ftype].param[i]), 
793                                nrbond, bonds, nrang, angles);
794           break;
795           default:
796             gmx_fatal(FARGS,"Automatic parameter generation not supported "
797                         "for %s atom %d",
798                         interaction_function[ftype].longname,
799                         plist[ftype].param[i].AI+1);
800           } /* switch */
801           if (bERROR)
802             gmx_fatal(FARGS,"Automatic parameter generation not supported "
803                         "for %s atom %d for this bonding configuration",
804                         interaction_function[ftype].longname,
805                         plist[ftype].param[i].AI+1);
806           sfree(bonds);
807           sfree(angles);
808           sfree(idihs);
809         } /* if bSet */
810       } /* for i */
811       if (debug && plist[ftype].nr)
812         fprintf(stderr,"Calculated parameters for %d out of %d %s atoms\n",
813                 nrset,plist[ftype].nr,interaction_function[ftype].longname);
814     } /* if IF_VSITE */
815
816   done_at2vsitebond(atoms->nr,at2vb);
817   
818   return nvsite;
819 }
820
821 void set_vsites_ptype(gmx_bool bVerbose, gmx_moltype_t *molt)
822 {
823   int ftype,i;
824   int nra,nrd;
825   t_ilist *il;
826   t_iatom *ia,avsite;
827   
828   if (bVerbose)
829     fprintf(stderr,"Setting particle type to V for virtual sites\n");
830   if (debug)
831     fprintf(stderr,"checking %d functypes\n",F_NRE);
832   for(ftype=0; ftype<F_NRE; ftype++) {
833     il = &molt->ilist[ftype];
834     if (interaction_function[ftype].flags & IF_VSITE) {
835       nra    = interaction_function[ftype].nratoms;
836       nrd    = il->nr;
837       ia     = il->iatoms;
838       
839       if (debug && nrd)
840         fprintf(stderr,"doing %d %s virtual sites\n",
841                 (nrd / (nra+1)),interaction_function[ftype].longname);
842       
843       for(i=0; (i<nrd); ) {
844         /* The virtual site */
845         avsite = ia[1];
846         molt->atoms.atom[avsite].ptype = eptVSite;
847         
848         i  += nra+1;
849         ia += nra+1;
850       }
851     }
852   }
853   
854 }
855
856 typedef struct { 
857   int ftype,parnr;
858 } t_pindex;
859
860 static void check_vsite_constraints(t_params *plist, 
861                                     int cftype, int vsite_type[])
862 {
863   int      i,k,n;
864   atom_id  atom;
865   t_params *ps;
866   
867   n=0;
868   ps = &(plist[cftype]);
869   for(i=0; (i<ps->nr); i++)
870     for(k=0; k<2; k++) {
871       atom = ps->param[i].a[k];
872       if (vsite_type[atom]!=NOTSET) {
873         fprintf(stderr,"ERROR: Cannot have constraint (%u-%u) with virtual site (%u)\n",
874                 ps->param[i].AI+1, ps->param[i].AJ+1, atom+1);
875         n++;
876       }
877     }
878   if (n)
879     gmx_fatal(FARGS,"There were %d virtual sites involved in constraints",n);
880 }
881
882 static void clean_vsite_bonds(t_params *plist, t_pindex pindex[], 
883                             int cftype, int vsite_type[])
884 {
885   int      ftype,i,j,parnr,k,l,m,n,nvsite,nOut,kept_i,vsnral,vsitetype;
886   int      nconverted,nremoved;
887   atom_id  atom,oatom,constr,at1,at2;
888   atom_id  vsiteatoms[MAXATOMLIST];
889   gmx_bool     bKeep,bRemove,bUsed,bPresent,bThisFD,bThisOUT,bAllFD,bFirstTwo;
890   t_params *ps;
891
892   if (cftype == F_CONNBONDS)
893     return;
894   
895   ps = &(plist[cftype]);
896   vsnral=0;
897   kept_i=0;
898   nconverted=0;
899   nremoved=0;
900   nOut=0;
901   for(i=0; (i<ps->nr); i++) { /* for all bonds in the plist */
902     bKeep=FALSE;
903     bRemove=FALSE;
904     bAllFD=TRUE;
905     /* check if all virtual sites are constructed from the same atoms */
906     nvsite=0;
907     if(debug) 
908       fprintf(debug,"constr %u %u:",ps->param[i].AI+1,ps->param[i].AJ+1);
909     for(k=0; (k<2) && !bKeep && !bRemove; k++) { 
910       /* for all atoms in the bond */
911       atom = ps->param[i].a[k];
912       if (vsite_type[atom]!=NOTSET) {
913         if(debug) {
914           fprintf(debug," d%d[%d: %d %d %d]",k,atom+1,
915                   plist[pindex[atom].ftype].param[pindex[atom].parnr].AJ+1,
916                   plist[pindex[atom].ftype].param[pindex[atom].parnr].AK+1,
917                   plist[pindex[atom].ftype].param[pindex[atom].parnr].AL+1);
918         }
919         nvsite++;
920         bThisFD = ( (pindex[atom].ftype == F_VSITE3FD ) ||
921                 (pindex[atom].ftype == F_VSITE3FAD) ||
922                 (pindex[atom].ftype == F_VSITE4FD ) ||
923                 (pindex[atom].ftype == F_VSITE4FDN ) );
924         bThisOUT= ( (pindex[atom].ftype == F_VSITE3OUT) &&
925                     (interaction_function[cftype].flags & IF_CONSTRAINT) );
926         bAllFD = bAllFD && bThisFD;
927         if (bThisFD || bThisOUT) {
928           if(debug)fprintf(debug," %s",bThisOUT?"out":"fd");
929           oatom = ps->param[i].a[1-k]; /* the other atom */
930           if ( vsite_type[oatom]==NOTSET &&
931                oatom==plist[pindex[atom].ftype].param[pindex[atom].parnr].AJ ){
932             /* if the other atom isn't a vsite, and it is AI */
933             bRemove=TRUE;
934             if (bThisOUT)
935               nOut++;
936             if(debug)fprintf(debug," D-AI");
937           }
938         }
939         if (!bRemove) {
940           if (nvsite==1) {
941             /* if this is the first vsite we encounter then
942                store construction atoms */
943             vsnral=NRAL(pindex[atom].ftype)-1;
944             for(m=0; (m<vsnral); m++)
945               vsiteatoms[m]=
946                 plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
947           } else {
948             /* if it is not the first then
949                check if this vsite is constructed from the same atoms */
950             if (vsnral == NRAL(pindex[atom].ftype)-1 )
951               for(m=0; (m<vsnral) && !bKeep; m++) {
952                 bPresent=FALSE;
953                 constr=
954                   plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
955                 for(n=0; (n<vsnral) && !bPresent; n++)
956                   if (constr == vsiteatoms[n])
957                     bPresent=TRUE;
958                 if (!bPresent) {
959                   bKeep=TRUE;
960                   if(debug)fprintf(debug," !present");
961                 }
962               }
963             else {
964               bKeep=TRUE;
965               if(debug)fprintf(debug," !same#at");
966             }
967           }
968         }
969       }
970     }
971     
972     if (bRemove) 
973       bKeep=FALSE;
974     else {
975       /* if we have no virtual sites in this bond, keep it */
976       if (nvsite==0) {
977         if (debug)fprintf(debug," no vsite");
978         bKeep=TRUE;
979       }
980     
981       /* check if all non-vsite atoms are used in construction: */
982       bFirstTwo=TRUE;
983       for(k=0; (k<2) && !bKeep; k++) { /* for all atoms in the bond */
984         atom = ps->param[i].a[k];
985         if (vsite_type[atom]==NOTSET) {
986           bUsed=FALSE;
987           for(m=0; (m<vsnral) && !bUsed; m++)
988             if (atom == vsiteatoms[m]) {
989               bUsed=TRUE;
990               bFirstTwo = bFirstTwo && m<2;
991             }
992           if (!bUsed) {
993             bKeep=TRUE;
994             if(debug)fprintf(debug," !used");
995           }
996         }
997       }
998       
999       if ( ! ( bAllFD && bFirstTwo ) )
1000         /* check if all constructing atoms are constrained together */
1001         for (m=0; m<vsnral && !bKeep; m++) { /* all constr. atoms */
1002           at1 = vsiteatoms[m];
1003           at2 = vsiteatoms[(m+1) % vsnral];
1004           bPresent=FALSE;
1005           for (ftype=0; ftype<F_NRE; ftype++)
1006             if ( interaction_function[ftype].flags & IF_CONSTRAINT )
1007               for (j=0; (j<plist[ftype].nr) && !bPresent; j++)
1008                 /* all constraints until one matches */
1009                 bPresent = ( ( (plist[ftype].param[j].AI == at1) &&
1010                                (plist[ftype].param[j].AJ == at2) ) || 
1011                              ( (plist[ftype].param[j].AI == at2) &&
1012                                (plist[ftype].param[j].AJ == at1) ) );
1013           if (!bPresent) {
1014             bKeep=TRUE;
1015             if(debug)fprintf(debug," !bonded");
1016           }
1017         }
1018     }
1019     
1020     if ( bKeep ) {
1021       if(debug)fprintf(debug," keeping");
1022       /* now copy the bond to the new array */
1023       memcpy(&(ps->param[kept_i]),
1024              &(ps->param[i]),(size_t)sizeof(ps->param[0]));
1025       kept_i++;
1026     } else if (IS_CHEMBOND(cftype)) {
1027       srenew(plist[F_CONNBONDS].param,plist[F_CONNBONDS].nr+1);
1028       memcpy(&(plist[F_CONNBONDS].param[plist[F_CONNBONDS].nr]),
1029              &(ps->param[i]),(size_t)sizeof(plist[F_CONNBONDS].param[0]));
1030       plist[F_CONNBONDS].nr++;
1031       nconverted++;
1032     } else
1033       nremoved++;
1034     if(debug)fprintf(debug,"\n");
1035   }
1036   
1037   if (nremoved)
1038     fprintf(stderr,"Removed   %4d %15ss with virtual sites, %5d left\n",
1039             nremoved, interaction_function[cftype].longname, kept_i);
1040   if (nconverted)
1041     fprintf(stderr,"Converted %4d %15ss with virtual sites to connections, %5d left\n",
1042             nconverted, interaction_function[cftype].longname, kept_i);
1043   if (nOut)
1044     fprintf(stderr,"Warning: removed %d %ss with vsite with %s construction\n"
1045             "         This vsite construction does not guarantee constant "
1046             "bond-length\n"
1047             "         If the constructions were generated by pdb2gmx ignore "
1048             "this warning\n",
1049             nOut, interaction_function[cftype].longname, 
1050             interaction_function[F_VSITE3OUT].longname );
1051   ps->nr=kept_i;
1052 }
1053
1054 static void clean_vsite_angles(t_params *plist, t_pindex pindex[], 
1055                                int cftype, int vsite_type[],
1056                                at2vsitecon_t *at2vc)
1057 {
1058   int      i,j,parnr,k,l,m,n,nvsite,kept_i,vsnral,vsitetype;
1059   atom_id  atom,constr,at1,at2;
1060   atom_id  vsiteatoms[MAXATOMLIST];
1061   gmx_bool     bKeep,bUsed,bPresent,bAll3FAD,bFirstTwo;
1062   t_params *ps;
1063   
1064   ps = &(plist[cftype]);
1065   vsnral=0;
1066   kept_i=0;
1067   for(i=0; (i<ps->nr); i++) { /* for all angles in the plist */
1068     bKeep=FALSE;
1069     bAll3FAD=TRUE;
1070     /* check if all virtual sites are constructed from the same atoms */
1071     nvsite=0;
1072     for(k=0; (k<3) && !bKeep; k++) { /* for all atoms in the angle */
1073       atom = ps->param[i].a[k];
1074       if (vsite_type[atom]!=NOTSET) {
1075         nvsite++;
1076         bAll3FAD = bAll3FAD && (pindex[atom].ftype == F_VSITE3FAD);
1077         if (nvsite==1) {
1078           /* store construction atoms of first vsite */
1079           vsnral=NRAL(pindex[atom].ftype)-1;
1080           for(m=0; (m<vsnral); m++)
1081             vsiteatoms[m]=
1082               plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
1083         } else 
1084           /* check if this vsite is constructed from the same atoms */
1085           if (vsnral == NRAL(pindex[atom].ftype)-1 )
1086             for(m=0; (m<vsnral) && !bKeep; m++) {
1087               bPresent=FALSE;
1088               constr=
1089                 plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
1090               for(n=0; (n<vsnral) && !bPresent; n++)
1091                 if (constr == vsiteatoms[n])
1092                   bPresent=TRUE;
1093               if (!bPresent)
1094                 bKeep=TRUE;
1095             }
1096           else
1097             bKeep=TRUE;
1098       }
1099     }
1100     
1101     /* keep all angles with no virtual sites in them or 
1102        with virtual sites with more than 3 constr. atoms */
1103     if ( nvsite == 0 && vsnral > 3 )
1104       bKeep=TRUE;
1105     
1106     /* check if all non-vsite atoms are used in construction: */
1107     bFirstTwo=TRUE;
1108     for(k=0; (k<3) && !bKeep; k++) { /* for all atoms in the angle */
1109       atom = ps->param[i].a[k];
1110       if (vsite_type[atom]==NOTSET) {
1111         bUsed=FALSE;
1112         for(m=0; (m<vsnral) && !bUsed; m++)
1113           if (atom == vsiteatoms[m]) {
1114             bUsed=TRUE;
1115             bFirstTwo = bFirstTwo && m<2;
1116           }
1117         if (!bUsed)
1118           bKeep=TRUE;
1119       }
1120     }
1121     
1122     if ( ! ( bAll3FAD && bFirstTwo ) )
1123       /* check if all constructing atoms are constrained together */
1124       for (m=0; m<vsnral && !bKeep; m++) { /* all constr. atoms */
1125         at1 = vsiteatoms[m];
1126         at2 = vsiteatoms[(m+1) % vsnral];
1127         bPresent=FALSE;
1128         for(j=0; j<at2vc[at1].nr; j++) {
1129           if (at2vc[at1].aj[j] == at2)
1130             bPresent = TRUE;
1131         }
1132         if (!bPresent)
1133           bKeep=TRUE;
1134       }
1135     
1136     if ( bKeep ) {
1137       /* now copy the angle to the new array */
1138       memcpy(&(ps->param[kept_i]),
1139              &(ps->param[i]),(size_t)sizeof(ps->param[0]));
1140       kept_i++;
1141     }
1142   }
1143   
1144   if (ps->nr != kept_i)
1145     fprintf(stderr,"Removed   %4d %15ss with virtual sites, %5d left\n",
1146             ps->nr-kept_i, interaction_function[cftype].longname, kept_i);
1147   ps->nr=kept_i;
1148 }
1149
1150 static void clean_vsite_dihs(t_params *plist, t_pindex pindex[], 
1151                            int cftype, int vsite_type[])
1152 {
1153   int      ftype,i,parnr,k,l,m,n,nvsite,kept_i,vsnral;
1154   atom_id  atom,constr;
1155   atom_id  vsiteatoms[3];
1156   gmx_bool     bKeep,bUsed,bPresent;
1157   t_params *ps;
1158   
1159   ps = &(plist[cftype]);
1160   
1161   vsnral=0;
1162   kept_i=0;
1163   for(i=0; (i<ps->nr); i++) { /* for all dihedrals in the plist */
1164     bKeep=FALSE;
1165     /* check if all virtual sites are constructed from the same atoms */
1166     nvsite=0;
1167     for(k=0; (k<4) && !bKeep; k++) { /* for all atoms in the dihedral */
1168       atom = ps->param[i].a[k];
1169       if (vsite_type[atom]!=NOTSET) {
1170         nvsite++;
1171         if (nvsite==1) {
1172           /* store construction atoms of first vsite */
1173           vsnral=NRAL(pindex[atom].ftype)-1;
1174           for(m=0; (m<vsnral); m++)
1175             vsiteatoms[m]=
1176               plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
1177           if (debug) {
1178             fprintf(debug,"dih w. vsite: %u %u %u %u\n",
1179                     ps->param[i].AI+1,ps->param[i].AJ+1,
1180                     ps->param[i].AK+1,ps->param[i].AL+1);
1181             fprintf(debug,"vsite %u from: %u %u %u\n",
1182                     atom+1,vsiteatoms[0]+1,vsiteatoms[1]+1,vsiteatoms[2]+1);
1183           }
1184         } else 
1185           /* check if this vsite is constructed from the same atoms */
1186           if (vsnral == NRAL(pindex[atom].ftype)-1 )
1187             for(m=0; (m<vsnral) && !bKeep; m++) {
1188               bPresent=FALSE;
1189               constr=
1190                 plist[pindex[atom].ftype].param[pindex[atom].parnr].a[m+1];
1191               for(n=0; (n<vsnral) && !bPresent; n++)
1192                 if (constr == vsiteatoms[n])
1193                   bPresent=TRUE;
1194               if (!bPresent)
1195                 bKeep=TRUE;
1196             }
1197       }
1198     }
1199     
1200     /* keep all dihedrals with no virtual sites in them */
1201     if (nvsite==0)
1202       bKeep=TRUE;
1203     
1204     /* check if all atoms in dihedral are either virtual sites, or used in 
1205        construction of virtual sites. If so, keep it, if not throw away: */
1206     for(k=0; (k<4) && !bKeep; k++) { /* for all atoms in the dihedral */
1207       atom = ps->param[i].a[k];
1208       if (vsite_type[atom]==NOTSET) {
1209         bUsed=FALSE;
1210         for(m=0; (m<vsnral) && !bUsed; m++)
1211           if (atom == vsiteatoms[m])
1212             bUsed=TRUE;
1213         if (!bUsed) {
1214           bKeep=TRUE;
1215           if (debug) fprintf(debug,"unused atom in dih: %u\n",atom+1);
1216         }
1217       }
1218     }
1219       
1220     if ( bKeep ) {
1221       memcpy(&(ps->param[kept_i]),
1222              &(ps->param[i]),(size_t)sizeof(ps->param[0]));
1223       kept_i++;
1224     }
1225   }
1226
1227   if (ps->nr != kept_i)
1228     fprintf(stderr,"Removed   %4d %15ss with virtual sites, %5d left\n", 
1229             ps->nr-kept_i, interaction_function[cftype].longname, kept_i);
1230   ps->nr=kept_i;
1231 }
1232
1233 void clean_vsite_bondeds(t_params *plist, int natoms, gmx_bool bRmVSiteBds)
1234 {
1235   int i,k,nvsite,ftype,vsite,parnr;
1236   int *vsite_type;
1237   t_pindex *pindex;
1238   at2vsitecon_t *at2vc;
1239
1240   pindex=0; /* avoid warnings */
1241   /* make vsite_type array */
1242   snew(vsite_type,natoms);
1243   for(i=0; i<natoms; i++)
1244     vsite_type[i]=NOTSET;
1245   nvsite=0;
1246   for(ftype=0; ftype<F_NRE; ftype++)
1247     if (interaction_function[ftype].flags & IF_VSITE) {
1248       nvsite+=plist[ftype].nr;
1249       i = 0;
1250       while (i < plist[ftype].nr) {
1251         vsite = plist[ftype].param[i].AI;
1252         if ( vsite_type[vsite] == NOTSET)
1253           vsite_type[vsite] = ftype;
1254         else
1255           gmx_fatal(FARGS,"multiple vsite constructions for atom %d",vsite+1);
1256         if (ftype == F_VSITEN) {
1257           while (i < plist[ftype].nr && plist[ftype].param[i].AI == vsite)
1258             i++;
1259         } else {
1260           i++;
1261         }
1262       }
1263     }
1264   
1265   /* the rest only if we have virtual sites: */
1266   if (nvsite) {
1267     fprintf(stderr,"Cleaning up constraints %swith virtual sites\n",
1268             bRmVSiteBds?"and constant bonded interactions ":"");
1269
1270     /* Make a reverse list to avoid ninteractions^2 operations */
1271     at2vc = make_at2vsitecon(natoms,plist);
1272
1273     snew(pindex,natoms);
1274     for(ftype=0; ftype<F_NRE; ftype++) {
1275       if ((interaction_function[ftype].flags & IF_VSITE) &&
1276           ftype != F_VSITEN) {
1277         for (parnr=0; (parnr<plist[ftype].nr); parnr++) {
1278           k=plist[ftype].param[parnr].AI;
1279           pindex[k].ftype=ftype;
1280           pindex[k].parnr=parnr;
1281         }
1282       }
1283     }
1284
1285     if (debug)
1286       for(i=0; i<natoms; i++)
1287         fprintf(debug,"atom %d vsite_type %s\n",i, 
1288                 vsite_type[i]==NOTSET ? "NOTSET" : 
1289                 interaction_function[vsite_type[i]].name);
1290     
1291     /* remove things with vsite atoms */
1292     for(ftype=0; ftype<F_NRE; ftype++)
1293       if ( ( ( interaction_function[ftype].flags & IF_BOND ) && bRmVSiteBds ) ||
1294            ( interaction_function[ftype].flags & IF_CONSTRAINT ) ) {
1295         if (interaction_function[ftype].flags & (IF_BTYPE | IF_CONSTRAINT) )
1296           clean_vsite_bonds (plist, pindex, ftype, vsite_type);
1297         else if (interaction_function[ftype].flags & IF_ATYPE)
1298           clean_vsite_angles(plist, pindex, ftype, vsite_type, at2vc);
1299         else if ( (ftype==F_PDIHS) || (ftype==F_IDIHS) )
1300           clean_vsite_dihs  (plist, pindex, ftype, vsite_type);
1301       }
1302     /* check if we have constraints left with virtual sites in them */
1303     for(ftype=0; ftype<F_NRE; ftype++)
1304       if (interaction_function[ftype].flags & IF_CONSTRAINT)
1305         check_vsite_constraints(plist, ftype, vsite_type);
1306
1307     done_at2vsitecon(natoms,at2vc);
1308   }
1309   sfree(pindex);
1310   sfree(vsite_type);
1311 }