Fix remaining copyright headers
[alexxy/gromacs.git] / src / gromacs / gmxana / addconf.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include "vec.h"
44 #include "macros.h"
45 #include "smalloc.h"
46 #include "addconf.h"
47 #include "force.h"
48 #include "gstat.h"
49 #include "names.h"
50 #include "nsgrid.h"
51 #include "mdatoms.h"
52 #include "nrnb.h"
53 #include "ns.h"
54 #include "mtop_util.h"
55 #include "chargegroup.h"
56
57 static real box_margin;
58
59 static real max_dist(rvec *x, real *r, int start, int end)
60 {
61     real maxd;
62     int  i, j;
63
64     maxd = 0;
65     for (i = start; i < end; i++)
66     {
67         for (j = i+1; j < end; j++)
68         {
69             maxd = max(maxd, sqrt(distance2(x[i], x[j]))+0.5*(r[i]+r[j]));
70         }
71     }
72
73     return 0.5*maxd;
74 }
75
76 static gmx_bool outside_box_minus_margin2(rvec x, matrix box)
77 {
78     return ( (x[XX] < 2*box_margin) || (x[XX] > box[XX][XX]-2*box_margin) ||
79              (x[YY] < 2*box_margin) || (x[YY] > box[YY][YY]-2*box_margin) ||
80              (x[ZZ] < 2*box_margin) || (x[ZZ] > box[ZZ][ZZ]-2*box_margin) );
81 }
82
83 static gmx_bool outside_box_plus_margin(rvec x, matrix box)
84 {
85     return ( (x[XX] < -box_margin) || (x[XX] > box[XX][XX]+box_margin) ||
86              (x[YY] < -box_margin) || (x[YY] > box[YY][YY]+box_margin) ||
87              (x[ZZ] < -box_margin) || (x[ZZ] > box[ZZ][ZZ]+box_margin) );
88 }
89
90 static int mark_res(int at, gmx_bool *mark, int natoms, t_atom *atom, int *nmark)
91 {
92     int resind;
93
94     resind = atom[at].resind;
95     while ( (at > 0) && (resind == atom[at-1].resind) )
96     {
97         at--;
98     }
99     while ( (at < natoms) && (resind == atom[at].resind) )
100     {
101         if (!mark[at])
102         {
103             mark[at] = TRUE;
104             (*nmark)++;
105         }
106         at++;
107     }
108
109     return at;
110 }
111
112 static real find_max_real(int n, real radius[])
113 {
114     int  i;
115     real rmax;
116
117     rmax = 0;
118     if (n > 0)
119     {
120         rmax = radius[0];
121         for (i = 1; (i < n); i++)
122         {
123             rmax = max(rmax, radius[i]);
124         }
125     }
126     return rmax;
127 }
128
129 static void combine_atoms(t_atoms *ap, t_atoms *as,
130                           rvec xp[], rvec *vp, rvec xs[], rvec *vs,
131                           t_atoms **a_comb, rvec **x_comb, rvec **v_comb)
132 {
133     t_atoms *ac;
134     rvec    *xc, *vc = NULL;
135     int      i, j, natot, res0;
136
137     /* Total number of atoms */
138     natot = ap->nr+as->nr;
139
140     snew(ac, 1);
141     init_t_atoms(ac, natot, FALSE);
142
143     snew(xc, natot);
144     if (vp && vs)
145     {
146         snew(vc, natot);
147     }
148
149     /* Fill the new structures */
150     for (i = j = 0; (i < ap->nr); i++, j++)
151     {
152         copy_rvec(xp[i], xc[j]);
153         if (vc)
154         {
155             copy_rvec(vp[i], vc[j]);
156         }
157         memcpy(&(ac->atom[j]), &(ap->atom[i]), sizeof(ap->atom[i]));
158         ac->atom[j].type = 0;
159     }
160     res0 = ap->nres;
161     for (i = 0; (i < as->nr); i++, j++)
162     {
163         copy_rvec(xs[i], xc[j]);
164         if (vc)
165         {
166             copy_rvec(vs[i], vc[j]);
167         }
168         memcpy(&(ac->atom[j]), &(as->atom[i]), sizeof(as->atom[i]));
169         ac->atom[j].type    = 0;
170         ac->atom[j].resind += res0;
171     }
172     ac->nr   = j;
173     ac->nres = ac->atom[j-1].resind+1;
174     /* Fill all elements to prevent uninitialized memory */
175     for (i = 0; i < ac->nr; i++)
176     {
177         ac->atom[i].m     = 1;
178         ac->atom[i].q     = 0;
179         ac->atom[i].mB    = 1;
180         ac->atom[i].qB    = 0;
181         ac->atom[i].type  = 0;
182         ac->atom[i].typeB = 0;
183         ac->atom[i].ptype = eptAtom;
184     }
185
186     /* Return values */
187     *a_comb = ac;
188     *x_comb = xc;
189     *v_comb = vc;
190 }
191
192 static t_forcerec *fr = NULL;
193
194 void do_nsgrid(FILE *fp, gmx_bool bVerbose,
195                matrix box, rvec x[], t_atoms *atoms, real rlong,
196                const output_env_t oenv)
197 {
198     gmx_mtop_t     *mtop;
199     gmx_localtop_t *top;
200     t_mdatoms      *md;
201     t_block        *cgs;
202     t_inputrec     *ir;
203     t_nrnb          nrnb;
204     t_commrec      *cr;
205     int            *cg_index;
206     gmx_moltype_t  *molt;
207     gmx_ffparams_t *ffp;
208     ivec           *nFreeze;
209     int             i, m, natoms;
210     rvec            box_size;
211     real           *lambda, *dvdl;
212
213     natoms = atoms->nr;
214
215     /* Charge group index */
216     snew(cg_index, natoms);
217     for (i = 0; (i < natoms); i++)
218     {
219         cg_index[i] = i;
220     }
221
222     /* Topology needs charge groups and exclusions */
223     snew(mtop, 1);
224     init_mtop(mtop);
225     mtop->natoms = natoms;
226     /* Make one moltype that contains the whol system */
227     mtop->nmoltype = 1;
228     snew(mtop->moltype, mtop->nmoltype);
229     molt        = &mtop->moltype[0];
230     molt->name  = mtop->name;
231     molt->atoms = *atoms;
232     stupid_fill_block(&molt->cgs, mtop->natoms, FALSE);
233     stupid_fill_blocka(&molt->excls, natoms);
234     /* Make one molblock for the whole system */
235     mtop->nmolblock = 1;
236     snew(mtop->molblock, mtop->nmolblock);
237     mtop->molblock[0].type       = 0;
238     mtop->molblock[0].nmol       = 1;
239     mtop->molblock[0].natoms_mol = natoms;
240     /* Initialize a single energy group */
241     mtop->groups.grps[egcENER].nr = 1;
242     mtop->groups.ngrpnr[egcENER]  = 0;
243     mtop->groups.grpnr[egcENER]   = NULL;
244
245     ffp = &mtop->ffparams;
246
247     ffp->ntypes = 1;
248     ffp->atnr   = 1;
249     ffp->reppow = 12;
250     snew(ffp->functype, 1);
251     snew(ffp->iparams, 1);
252     ffp->iparams[0].lj.c6  = 1;
253     ffp->iparams[0].lj.c12 = 1;
254
255     /* inputrec structure */
256     snew(ir, 1);
257     ir->coulombtype = eelCUT;
258     ir->vdwtype     = evdwCUT;
259     ir->ndelta      = 2;
260     ir->ns_type     = ensGRID;
261     snew(ir->opts.egp_flags, 1);
262
263     top = gmx_mtop_generate_local_top(mtop, ir);
264
265     /* Some nasty shortcuts */
266     cgs  = &(top->cgs);
267
268     /* mdatoms structure */
269     snew(nFreeze, 2);
270     snew(md, 1);
271     md = init_mdatoms(fp, mtop, FALSE);
272     atoms2md(mtop, ir, 0, NULL, 0, mtop->natoms, md);
273     sfree(nFreeze);
274
275     /* forcerec structure */
276     if (fr == NULL)
277     {
278         fr = mk_forcerec();
279     }
280     snew(cr, 1);
281     cr->nnodes   = 1;
282     /* cr->nthreads = 1; */
283
284     /*    ir->rlist       = ir->rcoulomb = ir->rvdw = rlong;
285        printf("Neighborsearching with a cut-off of %g\n",rlong);
286        init_forcerec(stdout,fr,ir,top,cr,md,box,FALSE,NULL,NULL,NULL,TRUE);*/
287     fr->cg0     = 0;
288     fr->hcg     = top->cgs.nr;
289     fr->nWatMol = 0;
290
291     /* Prepare for neighboursearching */
292     init_nrnb(&nrnb);
293
294     /* Init things dependent on parameters */
295     ir->rlistlong = ir->rlist = ir->rcoulomb = ir->rvdw = rlong;
296     /* create free energy data to avoid NULLs */
297     snew(ir->fepvals, 1);
298     printf("Neighborsearching with a cut-off of %g\n", rlong);
299     init_forcerec(stdout, oenv, fr, NULL, ir, mtop, cr, box,
300                   NULL, NULL, NULL, NULL, NULL, TRUE, -1);
301     if (debug)
302     {
303         pr_forcerec(debug, fr);
304     }
305
306     /* Calculate new stuff dependent on coords and box */
307     for (m = 0; (m < DIM); m++)
308     {
309         box_size[m] = box[m][m];
310     }
311     calc_shifts(box, fr->shift_vec);
312     put_charge_groups_in_box(fp, 0, cgs->nr, fr->ePBC, box, cgs, x, fr->cg_cm);
313
314     /* Do the actual neighboursearching */
315     snew(lambda, efptNR);
316     snew(dvdl, efptNR);
317     init_neighbor_list(fp, fr, md->homenr);
318     search_neighbours(fp, fr, box, top,
319                       &mtop->groups, cr, &nrnb, md, TRUE, FALSE);
320
321     if (debug)
322     {
323         dump_nblist(debug, cr, fr, 0);
324     }
325
326     if (bVerbose)
327     {
328         fprintf(stderr, "Successfully made neighbourlist\n");
329     }
330 }
331
332 gmx_bool bXor(gmx_bool b1, gmx_bool b2)
333 {
334     return (b1 && !b2) || (b2 && !b1);
335 }
336
337 void add_conf(t_atoms *atoms, rvec **x, rvec **v, real **r, gmx_bool bSrenew,
338               int ePBC, matrix box, gmx_bool bInsert,
339               t_atoms *atoms_solvt, rvec *x_solvt, rvec *v_solvt, real *r_solvt,
340               gmx_bool bVerbose, real rshell, int max_sol, const output_env_t oenv)
341 {
342     t_nblist       *nlist;
343     t_atoms        *atoms_all;
344     real            max_vdw, *r_prot, *r_all, n2, r2, ib1, ib2;
345     int             natoms_prot, natoms_solvt;
346     int             i, j, jj, m, j0, j1, jjj, jnres, jnr, inr, iprot, is1, is2;
347     int             prev, resnr, nresadd, d, k, ncells, maxincell;
348     int             dx0, dx1, dy0, dy1, dz0, dz1;
349     int             ntest, nremove, nkeep;
350     rvec            dx, xi, xj, xpp, *x_all, *v_all;
351     gmx_bool       *remove, *keep;
352     int             bSolSol;
353
354     natoms_prot  = atoms->nr;
355     natoms_solvt = atoms_solvt->nr;
356     if (natoms_solvt <= 0)
357     {
358         fprintf(stderr, "WARNING: Nothing to add\n");
359         return;
360     }
361
362     if (ePBC == epbcSCREW)
363     {
364         gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]);
365     }
366
367     if (bVerbose)
368     {
369         fprintf(stderr, "Calculating Overlap...\n");
370     }
371
372     /* Set margin around box edges to largest solvent dimension.
373      * The maximum distance between atoms in a solvent molecule should
374      * be calculated. At the moment a fudge factor of 3 is used.
375      */
376     r_prot     = *r;
377     box_margin = 3*find_max_real(natoms_solvt, r_solvt);
378     max_vdw    = max(3*find_max_real(natoms_prot, r_prot), box_margin);
379     fprintf(stderr, "box_margin = %g\n", box_margin);
380
381     snew(remove, natoms_solvt);
382
383     nremove = 0;
384     if (!bInsert)
385     {
386         for (i = 0; i < atoms_solvt->nr; i++)
387         {
388             if (outside_box_plus_margin(x_solvt[i], box) )
389             {
390                 i = mark_res(i, remove, atoms_solvt->nr, atoms_solvt->atom, &nremove);
391             }
392         }
393         fprintf(stderr, "Removed %d atoms that were outside the box\n", nremove);
394     }
395
396     /* Define grid stuff for genbox */
397     /* Largest VDW radius */
398     snew(r_all, natoms_prot+natoms_solvt);
399     for (i = j = 0; i < natoms_prot; i++, j++)
400     {
401         r_all[j] = r_prot[i];
402     }
403     for (i = 0; i < natoms_solvt; i++, j++)
404     {
405         r_all[j] = r_solvt[i];
406     }
407
408     /* Combine arrays */
409     combine_atoms(atoms, atoms_solvt, *x, v ? *v : NULL, x_solvt, v_solvt,
410                   &atoms_all, &x_all, &v_all);
411
412     /* Do neighboursearching step */
413     do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, max_vdw, oenv);
414
415     /* check solvent with solute */
416     nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
417     fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj);
418     for (bSolSol = 0; (bSolSol <= (bInsert ? 0 : 1)); bSolSol++)
419     {
420         ntest = nremove = 0;
421         fprintf(stderr, "Checking %s-Solvent overlap:",
422                 bSolSol ? "Solvent" : "Protein");
423         for (i = 0; (i < nlist->nri && nremove < natoms_solvt); i++)
424         {
425             inr = nlist->iinr[i];
426             j0  = nlist->jindex[i];
427             j1  = nlist->jindex[i+1];
428             rvec_add(x_all[inr], fr->shift_vec[nlist->shift[i]], xi);
429
430             for (j = j0; (j < j1 && nremove < natoms_solvt); j++)
431             {
432                 jnr = nlist->jjnr[j];
433                 copy_rvec(x_all[jnr], xj);
434
435                 /* Check solvent-protein and solvent-solvent */
436                 is1 = inr-natoms_prot;
437                 is2 = jnr-natoms_prot;
438
439                 /* Check if at least one of the atoms is a solvent that is not yet
440                  * listed for removal, and if both are solvent, that they are not in the
441                  * same residue.
442                  */
443                 if ((!bSolSol &&
444                      bXor((is1 >= 0), (is2 >= 0)) && /* One atom is protein */
445                      ((is1 < 0) || ((is1 >= 0) && !remove[is1])) &&
446                      ((is2 < 0) || ((is2 >= 0) && !remove[is2]))) ||
447
448                     (bSolSol  &&
449                      (is1 >= 0) && (!remove[is1]) &&                   /* is1 is solvent */
450                      (is2 >= 0) && (!remove[is2]) &&                   /* is2 is solvent */
451                      (bInsert ||                                       /* when inserting also check inside the box */
452                       (outside_box_minus_margin2(x_solvt[is1], box) && /* is1 on edge */
453                        outside_box_minus_margin2(x_solvt[is2], box))   /* is2 on edge */
454                      ) &&
455                      (atoms_solvt->atom[is1].resind !=                 /* Not the same residue */
456                       atoms_solvt->atom[is2].resind)))
457                 {
458
459                     ntest++;
460                     rvec_sub(xi, xj, dx);
461                     n2 = norm2(dx);
462                     r2 = sqr(r_all[inr]+r_all[jnr]);
463                     if (n2 < r2)
464                     {
465                         if (bInsert)
466                         {
467                             nremove = natoms_solvt;
468                             for (k = 0; k < nremove; k++)
469                             {
470                                 remove[k] = TRUE;
471                             }
472                         }
473                         /* Need only remove one of the solvents... */
474                         if (is2 >= 0)
475                         {
476                             (void) mark_res(is2, remove, natoms_solvt, atoms_solvt->atom,
477                                             &nremove);
478                         }
479                         else if (is1 >= 0)
480                         {
481                             (void) mark_res(is1, remove, natoms_solvt, atoms_solvt->atom,
482                                             &nremove);
483                         }
484                         else
485                         {
486                             fprintf(stderr, "Neither atom is solvent%d %d\n", is1, is2);
487                         }
488                     }
489                 }
490             }
491         }
492         if (!bInsert)
493         {
494             fprintf(stderr, " tested %d pairs, removed %d atoms.\n", ntest, nremove);
495         }
496     }
497     if (debug)
498     {
499         for (i = 0; i < natoms_solvt; i++)
500         {
501             fprintf(debug, "remove[%5d] = %s\n", i, bool_names[remove[i]]);
502         }
503     }
504
505     /* Search again, now with another cut-off */
506     if (rshell > 0)
507     {
508         do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, rshell, oenv);
509         nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
510         fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj);
511         nkeep = 0;
512         snew(keep, natoms_solvt);
513         for (i = 0; i < nlist->nri; i++)
514         {
515             inr = nlist->iinr[i];
516             j0  = nlist->jindex[i];
517             j1  = nlist->jindex[i+1];
518
519             for (j = j0; j < j1; j++)
520             {
521                 jnr = nlist->jjnr[j];
522
523                 /* Check solvent-protein and solvent-solvent */
524                 is1 = inr-natoms_prot;
525                 is2 = jnr-natoms_prot;
526
527                 /* Check if at least one of the atoms is a solvent that is not yet
528                  * listed for removal, and if both are solvent, that they are not in the
529                  * same residue.
530                  */
531                 if (is1 >= 0 && is2 < 0)
532                 {
533                     mark_res(is1, keep, natoms_solvt, atoms_solvt->atom, &nkeep);
534                 }
535                 else if (is1 < 0 && is2 >= 0)
536                 {
537                     mark_res(is2, keep, natoms_solvt, atoms_solvt->atom, &nkeep);
538                 }
539             }
540         }
541         fprintf(stderr, "Keeping %d solvent atoms after proximity check\n",
542                 nkeep);
543         for (i = 0; i < natoms_solvt; i++)
544         {
545             remove[i] = remove[i] || !keep[i];
546         }
547         sfree(keep);
548     }
549     /* count how many atoms and residues will be added and make space */
550     if (bInsert)
551     {
552         j     = atoms_solvt->nr;
553         jnres = atoms_solvt->nres;
554     }
555     else
556     {
557         j     = 0;
558         jnres = 0;
559         for (i = 0; ((i < atoms_solvt->nr) &&
560                      ((max_sol == 0) || (jnres < max_sol))); i++)
561         {
562             if (!remove[i])
563             {
564                 j++;
565                 if ((i == 0) ||
566                     (atoms_solvt->atom[i].resind != atoms_solvt->atom[i-1].resind))
567                 {
568                     jnres++;
569                 }
570             }
571         }
572     }
573     if (debug)
574     {
575         fprintf(debug, "Will add %d atoms in %d residues\n", j, jnres);
576     }
577     if (!bInsert)
578     {
579         /* Flag the remaing solvent atoms to be removed */
580         jjj = atoms_solvt->atom[i-1].resind;
581         for (; (i < atoms_solvt->nr); i++)
582         {
583             if (atoms_solvt->atom[i].resind > jjj)
584             {
585                 remove[i] = TRUE;
586             }
587             else
588             {
589                 j++;
590             }
591         }
592     }
593
594     if (bSrenew)
595     {
596         srenew(atoms->resinfo,  atoms->nres+jnres);
597         srenew(atoms->atomname, atoms->nr+j);
598         srenew(atoms->atom,     atoms->nr+j);
599         srenew(*x,              atoms->nr+j);
600         if (v)
601         {
602             srenew(*v,       atoms->nr+j);
603         }
604         srenew(*r,              atoms->nr+j);
605     }
606
607     /* add the selected atoms_solvt to atoms */
608     if (atoms->nr > 0)
609     {
610         resnr = atoms->resinfo[atoms->atom[atoms->nr-1].resind].nr;
611     }
612     else
613     {
614         resnr = 0;
615     }
616     prev    = -1;
617     nresadd = 0;
618     for (i = 0; i < atoms_solvt->nr; i++)
619     {
620         if (!remove[i])
621         {
622             if (prev == -1 ||
623                 atoms_solvt->atom[i].resind != atoms_solvt->atom[prev].resind)
624             {
625                 nresadd++;
626                 atoms->nres++;
627                 resnr++;
628                 atoms->resinfo[atoms->nres-1] =
629                     atoms_solvt->resinfo[atoms_solvt->atom[i].resind];
630                 atoms->resinfo[atoms->nres-1].nr = resnr;
631                 /* calculate shift of the solvent molecule using the first atom */
632                 copy_rvec(x_solvt[i], dx);
633                 put_atoms_in_box(ePBC, box, 1, &dx);
634                 rvec_dec(dx, x_solvt[i]);
635             }
636             atoms->atom[atoms->nr]     = atoms_solvt->atom[i];
637             atoms->atomname[atoms->nr] = atoms_solvt->atomname[i];
638             rvec_add(x_solvt[i], dx, (*x)[atoms->nr]);
639             if (v)
640             {
641                 copy_rvec(v_solvt[i], (*v)[atoms->nr]);
642             }
643             (*r)[atoms->nr]               = r_solvt[i];
644             atoms->atom[atoms->nr].resind = atoms->nres-1;
645             atoms->nr++;
646             prev = i;
647         }
648     }
649     if (bSrenew)
650     {
651         srenew(atoms->resinfo,  atoms->nres+nresadd);
652     }
653
654     if (bVerbose)
655     {
656         fprintf(stderr, "Added %d molecules\n", nresadd);
657     }
658
659     sfree(remove);
660     done_atom(atoms_all);
661     sfree(x_all);
662     sfree(v_all);
663 }