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