Parallel vs. sequentiual code: I get binary identical result (apart from comment...
[gromacs/qmmm-gamess-us.git] / src / tools / addconf.c
blob6380cacc59799ae598334274beb50fe0f241c57b
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * Green Red Orange Magenta Azure Cyan Skyblue
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <stdlib.h>
40 #include <string.h>
41 #include "vec.h"
42 #include "macros.h"
43 #include "smalloc.h"
44 #include "addconf.h"
45 #include "force.h"
46 #include "gstat.h"
47 #include "names.h"
48 #include "nsgrid.h"
49 #include "mdatoms.h"
50 #include "nrnb.h"
51 #include "ns.h"
52 #include "mtop_util.h"
53 #include "chargegroup.h"
55 static real box_margin;
57 static real max_dist(rvec *x, real *r, int start, int end)
59 real maxd;
60 int i,j;
62 maxd=0;
63 for(i=start; i<end; i++)
64 for(j=i+1; j<end; j++)
65 maxd=max(maxd,sqrt(distance2(x[i],x[j]))+0.5*(r[i]+r[j]));
67 return 0.5*maxd;
70 static void set_margin(t_atoms *atoms, rvec *x, real *r)
72 int i,d,start;
74 box_margin=0;
76 start=0;
77 for(i=0; i < atoms->nr; i++) {
78 if ( (i+1 == atoms->nr) ||
79 (atoms->atom[i+1].resind != atoms->atom[i].resind) ) {
80 d=max_dist(x,r,start,i+1);
81 if (debug && d>box_margin)
82 fprintf(debug,"getting margin from %s: %g\n",
83 *(atoms->resinfo[atoms->atom[i].resind].name),box_margin);
84 box_margin=max(box_margin,d);
85 start=i+1;
88 fprintf(stderr,"box_margin = %g\n",box_margin);
91 static bool outside_box_minus_margin2(rvec x,matrix box)
93 return ( (x[XX]<2*box_margin) || (x[XX]>box[XX][XX]-2*box_margin) ||
94 (x[YY]<2*box_margin) || (x[YY]>box[YY][YY]-2*box_margin) ||
95 (x[ZZ]<2*box_margin) || (x[ZZ]>box[ZZ][ZZ]-2*box_margin) );
98 static bool outside_box_plus_margin(rvec x,matrix box)
100 return ( (x[XX]<-box_margin) || (x[XX]>box[XX][XX]+box_margin) ||
101 (x[YY]<-box_margin) || (x[YY]>box[YY][YY]+box_margin) ||
102 (x[ZZ]<-box_margin) || (x[ZZ]>box[ZZ][ZZ]+box_margin) );
105 static int mark_res(int at, bool *mark, int natoms, t_atom *atom,int *nmark)
107 int resind;
109 resind = atom[at].resind;
110 while( (at > 0) && (resind==atom[at-1].resind) )
111 at--;
112 while( (at < natoms) && (resind==atom[at].resind) ) {
113 if (!mark[at]) {
114 mark[at]=TRUE;
115 (*nmark)++;
117 at++;
120 return at;
123 static real find_max_real(int n,real radius[])
125 int i;
126 real rmax;
128 rmax = 0;
129 if (n > 0) {
130 rmax = radius[0];
131 for(i=1; (i<n); i++)
132 rmax = max(rmax,radius[i]);
134 return rmax;
137 static void combine_atoms(t_atoms *ap,t_atoms *as,
138 rvec xp[],rvec *vp,rvec xs[],rvec *vs,
139 t_atoms **a_comb,rvec **x_comb,rvec **v_comb)
141 t_atoms *ac;
142 rvec *xc,*vc=NULL;
143 int i,j,natot,res0;
145 /* Total number of atoms */
146 natot = ap->nr+as->nr;
148 snew(ac,1);
149 init_t_atoms(ac,natot,FALSE);
151 snew(xc,natot);
152 if (vp && vs) snew(vc,natot);
154 /* Fill the new structures */
155 for(i=j=0; (i<ap->nr); i++,j++) {
156 copy_rvec(xp[i],xc[j]);
157 if (vc) copy_rvec(vp[i],vc[j]);
158 memcpy(&(ac->atom[j]),&(ap->atom[i]),sizeof(ap->atom[i]));
159 ac->atom[j].type = 0;
161 res0 = ap->nres;
162 for(i=0; (i<as->nr); i++,j++) {
163 copy_rvec(xs[i],xc[j]);
164 if (vc) copy_rvec(vs[i],vc[j]);
165 memcpy(&(ac->atom[j]),&(as->atom[i]),sizeof(as->atom[i]));
166 ac->atom[j].type = 0;
167 ac->atom[j].resind += res0;
169 ac->nr = j;
170 ac->nres = ac->atom[j-1].resind+1;
171 /* Fill all elements to prevent uninitialized memory */
172 for(i=0; i<ac->nr; i++) {
173 ac->atom[i].m = 1;
174 ac->atom[i].q = 0;
175 ac->atom[i].mB = 1;
176 ac->atom[i].qB = 0;
177 ac->atom[i].type = 0;
178 ac->atom[i].typeB = 0;
179 ac->atom[i].ptype = eptAtom;
182 /* Return values */
183 *a_comb = ac;
184 *x_comb = xc;
185 *v_comb = vc;
188 static t_forcerec *fr=NULL;
190 void do_nsgrid(FILE *fp,bool bVerbose,
191 matrix box,rvec x[],t_atoms *atoms,real rlong,
192 const output_env_t oenv)
194 gmx_mtop_t *mtop;
195 gmx_localtop_t *top;
196 t_mdatoms *md;
197 t_block *cgs;
198 t_inputrec *ir;
199 t_nrnb nrnb;
200 t_commrec *cr;
201 int *cg_index;
202 gmx_moltype_t *molt;
203 gmx_ffparams_t *ffp;
204 ivec *nFreeze;
205 int i,m,natoms;
206 rvec box_size;
207 real lambda=0,dvdlambda=0;
209 natoms = atoms->nr;
211 /* Charge group index */
212 snew(cg_index,natoms);
213 for(i=0; (i<natoms); i++)
214 cg_index[i]=i;
216 /* Topology needs charge groups and exclusions */
217 snew(mtop,1);
218 init_mtop(mtop);
219 mtop->natoms = natoms;
220 /* Make one moltype that contains the whol system */
221 mtop->nmoltype = 1;
222 snew(mtop->moltype,mtop->nmoltype);
223 molt = &mtop->moltype[0];
224 molt->name = mtop->name;
225 molt->atoms = *atoms;
226 stupid_fill_block(&molt->cgs,mtop->natoms,FALSE);
227 stupid_fill_blocka(&molt->excls,natoms);
228 /* Make one molblock for the whole system */
229 mtop->nmolblock = 1;
230 snew(mtop->molblock,mtop->nmolblock);
231 mtop->molblock[0].type = 0;
232 mtop->molblock[0].nmol = 1;
233 mtop->molblock[0].natoms_mol = natoms;
234 /* Initialize a single energy group */
235 mtop->groups.grps[egcENER].nr = 1;
236 mtop->groups.ngrpnr[egcENER] = 0;
237 mtop->groups.grpnr[egcENER] = NULL;
239 ffp = &mtop->ffparams;
241 ffp->ntypes = 1;
242 ffp->atnr = 1;
243 ffp->reppow = 12;
244 snew(ffp->functype,1);
245 snew(ffp->iparams,1);
246 ffp->iparams[0].lj.c6 = 1;
247 ffp->iparams[0].lj.c12 = 1;
249 /* inputrec structure */
250 snew(ir,1);
251 ir->coulombtype = eelCUT;
252 ir->vdwtype = evdwCUT;
253 ir->ndelta = 2;
254 ir->ns_type = ensGRID;
255 snew(ir->opts.egp_flags,1);
257 top = gmx_mtop_generate_local_top(mtop,ir);
259 /* Some nasty shortcuts */
260 cgs = &(top->cgs);
262 /* mdatoms structure */
263 snew(nFreeze,2);
264 snew(md,1);
265 md = init_mdatoms(fp,mtop,FALSE);
266 atoms2md(mtop,ir,0,NULL,0,mtop->natoms,md);
267 sfree(nFreeze);
269 /* forcerec structure */
270 if (fr == NULL)
271 fr = mk_forcerec();
272 snew(cr,1);
273 cr->nnodes = 1;
274 cr->nthreads = 1;
276 /* ir->rlist = ir->rcoulomb = ir->rvdw = rlong;
277 printf("Neighborsearching with a cut-off of %g\n",rlong);
278 init_forcerec(stdout,fr,ir,top,cr,md,box,FALSE,NULL,NULL,TRUE);*/
279 fr->cg0 = 0;
280 fr->hcg = top->cgs.nr;
281 fr->nWatMol = 0;
283 /* Prepare for neighboursearching */
284 init_nrnb(&nrnb);
286 /* Init things dependent on parameters */
287 ir->rlistlong = ir->rlist = ir->rcoulomb = ir->rvdw = rlong;
288 printf("Neighborsearching with a cut-off of %g\n",rlong);
289 init_forcerec(stdout,oenv,fr,NULL,ir,mtop,cr,box,FALSE,NULL,NULL,NULL,
290 TRUE,-1);
291 if (debug)
292 pr_forcerec(debug,fr,cr);
294 /* Calculate new stuff dependent on coords and box */
295 for(m=0; (m<DIM); m++)
296 box_size[m] = box[m][m];
297 calc_shifts(box,fr->shift_vec);
298 put_charge_groups_in_box(fp,0,cgs->nr,fr->ePBC,box,cgs,x,fr->cg_cm);
300 /* Do the actual neighboursearching */
301 init_neighbor_list(fp,fr,md->homenr);
302 search_neighbours(fp,fr,x,box,top,
303 &mtop->groups,cr,&nrnb,md,lambda,&dvdlambda,NULL,
304 TRUE,FALSE,FALSE,NULL);
306 if (debug)
307 dump_nblist(debug,cr,fr,0);
309 if (bVerbose)
310 fprintf(stderr,"Succesfully made neighbourlist\n");
313 bool bXor(bool b1,bool b2)
315 return (b1 && !b2) || (b2 && !b1);
318 void add_conf(t_atoms *atoms, rvec **x, rvec **v, real **r, bool bSrenew,
319 int ePBC, matrix box, bool bInsert,
320 t_atoms *atoms_solvt,rvec *x_solvt,rvec *v_solvt,real *r_solvt,
321 bool bVerbose,real rshell,int max_sol, const output_env_t oenv)
323 t_nblist *nlist;
324 t_atoms *atoms_all;
325 real max_vdw,*r_prot,*r_all,n2,r2,ib1,ib2;
326 int natoms_prot,natoms_solvt;
327 int i,j,jj,m,j0,j1,jjj,jnres,jnr,inr,iprot,is1,is2;
328 int prev,resnr,nresadd,d,k,ncells,maxincell;
329 int dx0,dx1,dy0,dy1,dz0,dz1;
330 int ntest,nremove,nkeep;
331 rvec dx,xi,xj,xpp,*x_all,*v_all;
332 bool *remove,*keep;
333 int bSolSol;
335 natoms_prot = atoms->nr;
336 natoms_solvt = atoms_solvt->nr;
337 if (natoms_solvt <= 0) {
338 fprintf(stderr,"WARNING: Nothing to add\n");
339 return;
342 if (ePBC == epbcSCREW)
343 gmx_fatal(FARGS,"Sorry, %s pbc is not yet supported",epbc_names[ePBC]);
345 if (bVerbose)
346 fprintf(stderr,"Calculating Overlap...\n");
348 /* Set margin around box edges to largest solvent dimension.
349 * The maximum distance between atoms in a solvent molecule should
350 * be calculated. At the moment a fudge factor of 3 is used.
352 r_prot = *r;
353 box_margin = 3*find_max_real(natoms_solvt,r_solvt);
354 max_vdw = max(3*find_max_real(natoms_prot,r_prot),box_margin);
355 fprintf(stderr,"box_margin = %g\n",box_margin);
357 snew(remove,natoms_solvt);
359 nremove = 0;
360 if (!bInsert) {
361 for(i=0; i<atoms_solvt->nr; i++)
362 if ( outside_box_plus_margin(x_solvt[i],box) )
363 i=mark_res(i,remove,atoms_solvt->nr,atoms_solvt->atom,&nremove);
364 fprintf(stderr,"Removed %d atoms that were outside the box\n",nremove);
367 /* Define grid stuff for genbox */
368 /* Largest VDW radius */
369 snew(r_all,natoms_prot+natoms_solvt);
370 for(i=j=0; i<natoms_prot; i++,j++)
371 r_all[j]=r_prot[i];
372 for(i=0; i<natoms_solvt; i++,j++)
373 r_all[j]=r_solvt[i];
375 /* Combine arrays */
376 combine_atoms(atoms,atoms_solvt,*x,v?*v:NULL,x_solvt,v_solvt,
377 &atoms_all,&x_all,&v_all);
379 /* Do neighboursearching step */
380 do_nsgrid(stdout,bVerbose,box,x_all,atoms_all,max_vdw,oenv);
382 /* check solvent with solute */
383 nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
384 fprintf(stderr,"nri = %d, nrj = %d\n",nlist->nri,nlist->nrj);
385 for(bSolSol=0; (bSolSol<=(bInsert ? 0 : 1)); bSolSol++) {
386 ntest = nremove = 0;
387 fprintf(stderr,"Checking %s-Solvent overlap:",
388 bSolSol ? "Solvent" : "Protein");
389 for(i=0; (i<nlist->nri && nremove<natoms_solvt); i++) {
390 inr = nlist->iinr[i];
391 j0 = nlist->jindex[i];
392 j1 = nlist->jindex[i+1];
393 rvec_add(x_all[inr],fr->shift_vec[nlist->shift[i]],xi);
395 for(j=j0; (j<j1 && nremove<natoms_solvt); j++) {
396 jnr = nlist->jjnr[j];
397 copy_rvec(x_all[jnr],xj);
399 /* Check solvent-protein and solvent-solvent */
400 is1 = inr-natoms_prot;
401 is2 = jnr-natoms_prot;
403 /* Check if at least one of the atoms is a solvent that is not yet
404 * listed for removal, and if both are solvent, that they are not in the
405 * same residue.
407 if ((!bSolSol &&
408 bXor((is1 >= 0),(is2 >= 0)) && /* One atom is protein */
409 ((is1 < 0) || ((is1 >= 0) && !remove[is1])) &&
410 ((is2 < 0) || ((is2 >= 0) && !remove[is2]))) ||
412 (bSolSol &&
413 (is1 >= 0) && (!remove[is1]) && /* is1 is solvent */
414 (is2 >= 0) && (!remove[is2]) && /* is2 is solvent */
415 (bInsert || /* when inserting also check inside the box */
416 (outside_box_minus_margin2(x_solvt[is1],box) && /* is1 on edge */
417 outside_box_minus_margin2(x_solvt[is2],box)) /* is2 on edge */
418 ) &&
419 (atoms_solvt->atom[is1].resind != /* Not the same residue */
420 atoms_solvt->atom[is2].resind))) {
422 ntest++;
423 rvec_sub(xi,xj,dx);
424 n2 = norm2(dx);
425 r2 = sqr(r_all[inr]+r_all[jnr]);
426 if (n2 < r2) {
427 if (bInsert) {
428 nremove = natoms_solvt;
429 for(k=0; k<nremove; k++) {
430 remove[k] = TRUE;
433 /* Need only remove one of the solvents... */
434 if (is2 >= 0)
435 (void) mark_res(is2,remove,natoms_solvt,atoms_solvt->atom,
436 &nremove);
437 else if (is1 >= 0)
438 (void) mark_res(is1,remove,natoms_solvt,atoms_solvt->atom,
439 &nremove);
440 else
441 fprintf(stderr,"Neither atom is solvent%d %d\n",is1,is2);
446 if (!bInsert) {
447 fprintf(stderr," tested %d pairs, removed %d atoms.\n",ntest,nremove);
450 if (debug)
451 for(i=0; i<natoms_solvt; i++)
452 fprintf(debug,"remove[%5d] = %s\n",i,bool_names[remove[i]]);
454 /* Search again, now with another cut-off */
455 if (rshell > 0) {
456 do_nsgrid(stdout,bVerbose,box,x_all,atoms_all,rshell,oenv);
457 nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
458 fprintf(stderr,"nri = %d, nrj = %d\n",nlist->nri,nlist->nrj);
459 nkeep = 0;
460 snew(keep,natoms_solvt);
461 for(i=0; i<nlist->nri; i++) {
462 inr = nlist->iinr[i];
463 j0 = nlist->jindex[i];
464 j1 = nlist->jindex[i+1];
466 for(j=j0; j<j1; j++) {
467 jnr = nlist->jjnr[j];
469 /* Check solvent-protein and solvent-solvent */
470 is1 = inr-natoms_prot;
471 is2 = jnr-natoms_prot;
473 /* Check if at least one of the atoms is a solvent that is not yet
474 * listed for removal, and if both are solvent, that they are not in the
475 * same residue.
477 if (is1>=0 && is2<0)
478 mark_res(is1,keep,natoms_solvt,atoms_solvt->atom,&nkeep);
479 else if (is1<0 && is2>=0)
480 mark_res(is2,keep,natoms_solvt,atoms_solvt->atom,&nkeep);
483 fprintf(stderr,"Keeping %d solvent atoms after proximity check\n",
484 nkeep);
485 for (i=0; i<natoms_solvt; i++)
486 remove[i] = remove[i] || !keep[i];
487 sfree(keep);
489 /* count how many atoms and residues will be added and make space */
490 if (bInsert) {
491 j = atoms_solvt->nr;
492 jnres = atoms_solvt->nres;
493 } else {
494 j = 0;
495 jnres = 0;
496 for (i=0; ((i<atoms_solvt->nr) &&
497 ((max_sol == 0) || (jnres < max_sol))); i++) {
498 if (!remove[i]) {
499 j++;
500 if ((i == 0) ||
501 (atoms_solvt->atom[i].resind != atoms_solvt->atom[i-1].resind))
502 jnres++;
506 if (debug)
507 fprintf(debug,"Will add %d atoms in %d residues\n",j,jnres);
508 if (!bInsert) {
509 /* Flag the remaing solvent atoms to be removed */
510 jjj = atoms_solvt->atom[i-1].resind;
511 for ( ; (i<atoms_solvt->nr); i++) {
512 if (atoms_solvt->atom[i].resind > jjj)
513 remove[i] = TRUE;
514 else
515 j++;
519 if (bSrenew) {
520 srenew(atoms->resinfo, atoms->nres+jnres);
521 srenew(atoms->atomname, atoms->nr+j);
522 srenew(atoms->atom, atoms->nr+j);
523 srenew(*x, atoms->nr+j);
524 if (v) srenew(*v, atoms->nr+j);
525 srenew(*r, atoms->nr+j);
528 /* add the selected atoms_solvt to atoms */
529 if (atoms->nr > 0) {
530 resnr = atoms->resinfo[atoms->atom[atoms->nr-1].resind].nr;
531 } else {
532 resnr = 0;
534 prev = -1;
535 nresadd = 0;
536 for (i=0; i<atoms_solvt->nr; i++) {
537 if (!remove[i]) {
538 if (prev == -1 ||
539 atoms_solvt->atom[i].resind != atoms_solvt->atom[prev].resind) {
540 nresadd ++;
541 atoms->nres++;
542 resnr++;
543 atoms->resinfo[atoms->nres-1] =
544 atoms_solvt->resinfo[atoms_solvt->atom[i].resind];
545 atoms->resinfo[atoms->nres-1].nr = resnr;
546 /* calculate shift of the solvent molecule using the first atom */
547 copy_rvec(x_solvt[i],dx);
548 put_atoms_in_box(box,1,&dx);
549 rvec_dec(dx,x_solvt[i]);
551 atoms->atom[atoms->nr] = atoms_solvt->atom[i];
552 atoms->atomname[atoms->nr] = atoms_solvt->atomname[i];
553 rvec_add(x_solvt[i],dx,(*x)[atoms->nr]);
554 if (v) copy_rvec(v_solvt[i],(*v)[atoms->nr]);
555 (*r)[atoms->nr] = r_solvt[i];
556 atoms->atom[atoms->nr].resind = atoms->nres-1;
557 atoms->nr++;
558 prev=i;
561 if (bSrenew)
562 srenew(atoms->resinfo, atoms->nres+nresadd);
564 if (bVerbose)
565 fprintf(stderr,"Added %d molecules\n",nresadd);
567 sfree(remove);
568 done_atom(atoms_all);
569 sfree(x_all);
570 sfree(v_all);