Upped the version to 3.2.0
[gromacs.git] / src / kernel / genhydro.c
blobe345718097353d25e0323233845b6f6521b3ab7b
1 /*
2 * $Id$
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 3.2.0
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
36 #include <time.h>
37 #include <ctype.h>
38 #include "assert.h"
39 #include "sysstuff.h"
40 #include "typedefs.h"
41 #include "smalloc.h"
42 #include "copyrite.h"
43 #include "string2.h"
44 #include "confio.h"
45 #include "symtab.h"
46 #include "vec.h"
47 #include "statutil.h"
48 #include "futil.h"
49 #include "fatal.h"
50 #include "physics.h"
51 #include "calch.h"
52 #include "genhydro.h"
53 #include "h_db.h"
54 #include "ter_db.h"
55 #include "resall.h"
56 #include "pgutil.h"
58 static void copy_atom(t_atoms *atoms1,int a1,t_atoms *atoms2,int a2)
60 atoms2->atom[a2] = atoms1->atom[a1];
61 snew(atoms2->atomname[a2],1);
62 *atoms2->atomname[a2]=strdup(*atoms1->atomname[a1]);
65 atom_id pdbasearch_atom(char *name,int resnr,t_atoms *pdba)
67 int i;
69 for(i=0; (i<pdba->nr) && (pdba->atom[i].resnr != resnr); i++)
72 return search_atom(name,i,pdba->nr,pdba->atom,pdba->atomname);
75 void hacksearch_atom(int *ii, int *jj, char *name, int nab[], t_hack *ab[],
76 int resnr, t_atoms *pdba)
78 int i,j;
80 *ii=-1;
81 if (name[0] == '-') {
82 name++;
83 resnr--;
85 for(i=0; (i<pdba->nr) && (pdba->atom[i].resnr != resnr); i++)
87 for( ; (i<pdba->nr) && (pdba->atom[i].resnr == resnr) && (*ii<0); i++)
88 for(j=0; (j < nab[i]) && (*ii<0); j++)
89 if (ab[i][j].nname && strcmp(name,ab[i][j].nname) == 0) {
90 *ii=i;
91 *jj=j;
94 return;
97 void dump_ab(FILE *out,int natom,int nab[], t_hack *ab[], bool bHeader)
99 int i,j;
101 #define SS(s) (s)?(s):"-"
102 /* dump ab */
103 if (bHeader)
104 fprintf(out,"ADDBLOCK (t_hack) natom=%d\n"
105 "%4s %2s %-4s %-4s %2s %-4s %-4s %-4s %-4s %1s %s\n",
106 natom,"atom","nr","old","new","tp","ai","aj","ak","al","a","x");
107 for(i=0; i<natom; i++)
108 for(j=0; j<nab[i]; j++)
109 fprintf(out,"%4d %2d %-4s %-4s %2d %-4s %-4s %-4s %-4s %s %g %g %g\n",
110 i+1, ab[i][j].nr, SS(ab[i][j].oname), SS(ab[i][j].nname),
111 ab[i][j].tp,
112 SS(ab[i][j].AI), SS(ab[i][j].AJ),
113 SS(ab[i][j].AK), SS(ab[i][j].AL),
114 ab[i][j].atom?"+":"",
115 ab[i][j].newx[XX], ab[i][j].newx[YY], ab[i][j].newx[ZZ]);
116 #undef SS
119 static t_hackblock *get_hackblocks(t_atoms *pdba, int nah, t_hackblock ah[],
120 int nterpairs,
121 t_hackblock **ntdb, t_hackblock **ctdb,
122 int *rN, int *rC)
124 int i,rnr;
125 t_hackblock *hb,*ahptr;
127 /* make space */
128 snew(hb,pdba->nres);
129 /* first the termini */
130 for(i=0; i<nterpairs; i++) {
131 copy_t_hackblock(ntdb[i], &hb[rN[i]]);
132 merge_t_hackblock(ctdb[i], &hb[rC[i]]);
134 /* then the whole hdb */
135 for(rnr=0; rnr < pdba->nres; rnr++) {
136 ahptr=search_h_db(nah,ah,*pdba->resname[rnr]);
137 if ( ahptr ) {
138 if (hb[rnr].name==NULL)
139 hb[rnr].name=strdup(ahptr->name);
140 merge_hacks(ahptr, &hb[rnr]);
143 return hb;
146 static const char Hnum[] = "123456";
148 static void expand_hackblocks_one(t_hackblock *hbr, char *atomname,
149 int *nabi, t_hack **abi, bool bN, bool bC)
151 int j, k, l, d;
152 bool bIgnore;
154 /* we'll recursively add atoms to atoms */
155 for(j=0; j < hbr->nhack; j++) {
156 /* first check if we're in the N- or C-terminus, then we should ignore
157 all hacks involving atoms from resp. previous or next residue
158 (i.e. which name begins with '-' (N) or '+' (C) */
159 bIgnore = FALSE;
160 if ( bN ) /* N-terminus: ignore '-' */
161 for(k=0; k<4 && hbr->hack[j].a[k] && !bIgnore; k++)
162 bIgnore = hbr->hack[j].a[k][0]=='-';
163 if ( bC ) /* C-terminus: ignore '+' */
164 for(k=0; k<4 && hbr->hack[j].a[k] && !bIgnore; k++)
165 bIgnore = hbr->hack[j].a[k][0]=='+';
166 /* must be either hdb entry (tp>0) or add from tdb (oname==NULL)
167 and first control aton (AI) matches this atom or
168 delete/replace from tdb (oname!=NULL) and oname matches this atom */
169 if (debug) fprintf(debug," %s",
170 hbr->hack[j].oname?hbr->hack[j].oname:hbr->hack[j].AI);
171 if ( !bIgnore &&
172 ( ( ( hbr->hack[j].tp > 0 || hbr->hack[j].oname==NULL ) &&
173 strcmp(atomname, hbr->hack[j].AI) == 0 ) ||
174 ( hbr->hack[j].oname!=NULL &&
175 strcmp(atomname, hbr->hack[j].oname) == 0) ) ) {
176 /* now expand all hacks for this atom */
177 if (debug) fprintf(debug," +%dh",hbr->hack[j].nr);
178 srenew(*abi,*nabi + hbr->hack[j].nr);
179 for(k=0; k < hbr->hack[j].nr; k++) {
180 copy_t_hack(&hbr->hack[j], &(*abi)[*nabi + k]);
181 for(d=0; d<DIM; d++)
182 (*abi)[*nabi + k].newx[d]=NOTSET;
183 /* if we're adding (oname==NULL) and don't have a new name (nname)
184 yet, build it from atomname */
185 if ( (*abi)[*nabi + k].nname==NULL ) {
186 if ( (*abi)[*nabi + k].oname==NULL ) {
187 (*abi)[*nabi + k].nname=strdup(atomname);
188 (*abi)[*nabi + k].nname[0]='H';
190 } else {
191 sfree((*abi)[*nabi + k].nname);
192 (*abi)[*nabi + k].nname=strdup(hbr->hack[j].nname);
194 /* if adding more than one atom, number them */
195 if ( hbr->hack[j].nr > 1 ) {
196 l = strlen((*abi)[*nabi + k].nname);
197 srenew((*abi)[*nabi + k].nname, l+2);
198 (*abi)[*nabi + k].nname[l] = Hnum[k]; /* 1, 2, 3 .... */
199 (*abi)[*nabi + k].nname[l+1] = '\0';
202 (*nabi) += hbr->hack[j].nr;
204 /* add hacks to atoms we've just added */
205 if ( hbr->hack[j].tp > 0 || hbr->hack[j].oname==NULL )
206 for(k=0; k < hbr->hack[j].nr; k++)
207 expand_hackblocks_one(hbr, (*abi)[*nabi-hbr->hack[j].nr+k].nname,
208 nabi, abi, bN, bC);
213 static void expand_hackblocks(t_atoms *pdba, t_hackblock hb[],
214 int nab[], t_hack *ab[],
215 int nterpairs, int *rN, int *rC)
217 int i,j;
218 bool bN,bC;
220 for(i=0; i < pdba->nr; i++) {
221 bN = FALSE;
222 for(j=0; j<nterpairs && !bN; j++)
223 bN = pdba->atom[i].resnr==rN[j];
224 bC = FALSE;
225 for(j=0; j<nterpairs && !bC; j++)
226 bC = pdba->atom[i].resnr==rC[j];
228 /* add hacks to this atom */
229 expand_hackblocks_one(&hb[pdba->atom[i].resnr], *pdba->atomname[i],
230 &nab[i], &ab[i], bN, bC);
232 if (debug) fprintf(debug,"\n");
235 static int check_atoms_present(t_atoms *pdba, int nab[], t_hack *ab[])
237 int i, j, k, d, rnr, nadd;
239 nadd=0;
240 for(i=0; i < pdba->nr; i++) {
241 rnr = pdba->atom[i].resnr;
242 for(j=0; j<nab[i]; j++)
243 if ( ab[i][j].oname==NULL ) {
244 /* we're adding */
245 assert(ab[i][j].nname!=NULL);
246 /* check if the atom is already present */
247 k=pdbasearch_atom(ab[i][j].nname, rnr, pdba);
248 if ( k != -1 ) {
249 /* we found the added atom, so move the hack there: */
250 srenew(ab[k], nab[k]+1);
251 ab[k][nab[k]] = ab[i][j];
252 ab[k][nab[k]].oname = strdup(ab[k][nab[k]].nname);
253 /* reset any possible new coordinates: */
254 for(d=0; d<DIM; d++)
255 ab[k][nab[k]].newx[d]=NOTSET;
256 /* keep count */
257 nab[k]++;
258 /* remove the hack from this atom: */
259 for(k=j+1; k<nab[i]; k++)
260 ab[i][k-1] = ab[i][k];
261 /* keep count */
262 nab[i]--;
263 j--;
264 srenew(ab[i], nab[i]);
265 } else
266 /* count how many atoms we'll add */
267 nadd++;
268 } else if ( ab[i][j].nname==NULL )
269 /* we're deleting */
270 nadd--;
273 return nadd;
276 static void calc_all_pos(t_atoms *pdba, rvec x[], int nab[], t_hack *ab[])
278 int i, j, ii, jj, m, ia, d, rnr;
279 rvec xa[4]; /* control atoms for calc_h_pos */
280 rvec xh[3]; /* hydrogen positions from calc_h_pos */
282 for(i=0; i < pdba->nr; i++) {
283 rnr = pdba->atom[i].resnr;
284 for(j=0; j < nab[i]; j+=ab[i][j].nr) {
285 /* check if we're adding: */
286 if (ab[i][j].oname==NULL && ab[i][j].tp > 0) {
287 for(m=0; m<ncontrol[ab[i][j].tp]; m++) {
288 ia = pdbasearch_atom(ab[i][j].a[m], rnr, pdba);
289 if (ia < 0) {
290 /* not found in original atoms, might still be in t_hack (ab) */
291 hacksearch_atom(&ii, &jj, ab[i][j].a[m], nab, ab, rnr, pdba);
292 if (ii < 0)
293 fatal_error(0,"Atom %s not found in residue %s%d"
294 " while adding hydrogens",
295 ab[i][j].a[m],*pdba->resname[rnr],rnr+1);
296 else
297 copy_rvec(ab[ii][jj].newx, xa[m]);
298 } else
299 copy_rvec(x[ia], xa[m]);
301 for(m=0; m<3; m++)
302 for(d=0; d<DIM; d++)
303 if (m<ab[i][j].nr)
304 xh[m][d] = 0;
305 else
306 xh[m][d] = NOTSET;
307 calc_h_pos(ab[i][j].tp, xa, xh);
308 for(m=0; m<ab[i][j].nr; m++)
309 copy_rvec(xh[m],ab[i][j+m].newx);
315 int add_h(t_atoms **pdbaptr, rvec *xptr[],
316 int nah, t_hackblock ah[],
317 int nterpairs, t_hackblock **ntdb, t_hackblock **ctdb,
318 int *rN, int *rC, int **nabptr, t_hack ***abptr,
319 bool bUpdate_pdba, bool bKeep_old_pdba)
321 t_atoms *newpdba=NULL,*pdba=NULL;
322 bool bSet;
323 int nadd;
324 int i,newi,j,d,natoms;
325 int *nab=NULL;
326 t_hack **ab=NULL;
327 t_hackblock *hb;
328 rvec *xn;
329 bool bKeep_ab;
331 /* set flags for adding hydrogens (accoring to hdb) */
332 pdba=*pdbaptr;
333 natoms=pdba->nr;
335 if (nabptr && abptr) {
336 /* the first time these will be pointers to NULL, but we will
337 return in them the completed arrays, which we will get back
338 the second time */
339 nab = *nabptr;
340 ab = *abptr;
341 bKeep_ab=TRUE;
342 if (debug) fprintf(debug,"pointer to ab found\n");
343 } else
344 bKeep_ab=FALSE;
346 if (nab && ab) {
347 /* WOW, everything was already figured out */
348 bUpdate_pdba = FALSE;
349 if (debug) fprintf(debug,"pointer to non-null ab found\n");
350 } else {
351 /* We'll have to do all the hard work */
352 bUpdate_pdba = TRUE;
353 /* first get all the hackblocks for each residue: */
354 hb = get_hackblocks(pdba, nah, ah, nterpairs, ntdb, ctdb, rN, rC);
355 if (debug) dump_hb(debug, pdba->nres, hb);
357 /* expand the hackblocks to atom level */
358 snew(nab,natoms);
359 snew(ab,natoms);
360 expand_hackblocks(pdba, hb, nab, ab, nterpairs, rN, rC);
361 free_t_hackblock(pdba->nres, &hb);
364 if (debug) {
365 fprintf(debug,"before calc_all_pos\n");
366 dump_ab(debug, natoms, nab, ab, TRUE);
369 /* Now calc the positions */
370 calc_all_pos(pdba, *xptr, nab, ab);
372 if (debug) {
373 fprintf(debug,"after calc_all_pos\n");
374 dump_ab(debug, natoms, nab, ab, TRUE);
377 if (bUpdate_pdba) {
378 /* we don't have to add atoms that are already present in pdba,
379 so we will remove them from the ab (t_hack) */
380 nadd = check_atoms_present(pdba, nab, ab);
381 if (debug) {
382 fprintf(debug, "removed add hacks that were already in pdba:\n");
383 dump_ab(debug, natoms, nab, ab, TRUE);
384 fprintf(debug, "will be adding %d atoms\n",nadd);
387 /* Copy old atoms, making space for new ones */
388 snew(newpdba,1);
389 init_t_atoms(newpdba,natoms+nadd,FALSE);
390 newpdba->nres = pdba->nres;
391 sfree(newpdba->resname);
392 newpdba->resname = pdba->resname;
393 } else {
394 nadd = 0;
396 if (debug) fprintf(debug,"snew xn for %d old + %d new atoms %d total)\n",
397 natoms, nadd, natoms+nadd);
398 snew(xn,natoms+nadd);
399 newi=0;
400 for(i=0; (i<natoms); i++) {
401 /* check if this atom wasn't scheduled for deletion */
402 if ( nab[i]==0 || ab[i][0].nname!=NULL ) {
403 if (newi >= natoms+nadd) {
404 nadd+=10;
405 srenew(xn,natoms+nadd);
407 if (debug) fprintf(debug,"(%3d) %3d %4s %4s%3d %3d",
408 i+1, newi+1, *pdba->atomname[i],
409 *pdba->resname[pdba->atom[i].resnr],
410 pdba->atom[i].resnr+1, nab[i]);
411 if (bUpdate_pdba)
412 copy_atom(pdba,i, newpdba,newi);
413 copy_rvec((*xptr)[i],xn[newi]);
414 /* process the hacks for this atom */
415 for(j=0; j<nab[i]; j++) {
416 if ( ab[i][j].oname==NULL ) { /* add */
417 newi++;
418 if (newi >= natoms+nadd) {
419 nadd+=10;
420 srenew(xn,natoms+nadd);
422 if (bUpdate_pdba)
423 newpdba->atom[newi].resnr=pdba->atom[i].resnr;
424 if (debug) fprintf(debug," + %d",newi+1);
426 if ( ab[i][j].nname!=NULL ) { /* add or replace */
427 if (bUpdate_pdba) {
428 snew(newpdba->atomname[newi],1);
429 *newpdba->atomname[newi]=strdup(ab[i][j].nname);
430 if ( ab[i][j].oname!=NULL && ab[i][j].atom ) { /* replace */
431 /* newpdba->atom[newi].m = ab[i][j].atom->m; */
432 /* newpdba->atom[newi].q = ab[i][j].atom->q; */
433 /* newpdba->atom[newi].type = ab[i][j].atom->type; */
436 bSet=TRUE;
437 for(d=0; d<DIM; d++)
438 bSet = bSet && ab[i][j].newx[d]!=NOTSET;
439 if (bSet)
440 copy_rvec(ab[i][j].newx, xn[newi]);
441 if (bUpdate_pdba && debug)
442 fprintf(debug," %s %g %g",*newpdba->atomname[newi],
443 newpdba->atom[newi].m,newpdba->atom[newi].q);
446 newi++;
447 if (debug) fprintf(debug,"\n");
451 if ( bKeep_ab ) {
452 *nabptr=nab;
453 *abptr=ab;
454 } else {
455 /* Clean up */
456 for(i=0; i<natoms; i++)
457 free_t_hack(nab[i], &ab[i]);
458 sfree(nab);
459 sfree(ab);
462 if ( bUpdate_pdba ) {
463 if ( !bKeep_old_pdba ) {
464 for(i=0; i < natoms; i++) {
465 sfree(*(pdba->atomname[i]));
466 /* sfree(pdba->atomname[i]); */
468 sfree(pdba->atomname);
469 sfree(pdba->atom);
470 sfree(pdba->pdbinfo);
471 done_block(&(pdba->excl));
472 sfree(pdba);
474 *pdbaptr=newpdba;
475 } else
476 nadd = newi-natoms;
478 sfree(*xptr);
479 *xptr=xn;
481 return natoms+nadd;
484 void deprotonate(t_atoms *atoms,rvec *x)
486 int i,j;
488 j=0;
489 for(i=0; i<atoms->nr; i++) {
490 if ( (*atoms->atomname[i])[0] != 'H' ) {
491 atoms->atomname[j]=atoms->atomname[i];
492 atoms->atom[j]=atoms->atom[i];
493 copy_rvec(x[i],x[j]);
494 j++;
497 atoms->nr=j;
500 int protonate(t_atoms **atomsptr,rvec **xptr,t_protonate *protdata)
502 #define NTERPAIRS 1
503 t_atoms *atoms;
504 bool bUpdate_pdba,bKeep_old_pdba;
505 int nadd;
507 atoms=NULL;
508 if ( !protdata->bInit ) {
509 if (debug) fprintf(debug,"protonate: Initializing protdata\n");
510 /* set forcefield to use: */
511 strcpy(protdata->FF,"ffgmx2");
512 /* get the databases: */
513 protdata->nah=read_h_db(protdata->FF,&protdata->ah);
514 open_symtab(&protdata->tab);
515 protdata->atype=read_atype(protdata->FF,&protdata->tab);
516 if(read_ter_db(protdata->FF,'n',&protdata->ntdb,protdata->atype) < 4)
517 fatal_error(0,"no n-terminus db");
518 if(read_ter_db(protdata->FF,'c',&protdata->ctdb,protdata->atype) < 2)
519 fatal_error(0,"no c-terminus db");
521 /* set terminus types: -NH3+ (different for Proline) and -COO- */
522 atoms=*atomsptr;
523 snew(protdata->sel_ntdb, NTERPAIRS);
524 snew(protdata->sel_ctdb, NTERPAIRS);
525 if (strncmp(*atoms->resname[atoms->atom[atoms->nr-1].resnr],"PRO",3)==0)
526 protdata->sel_ntdb[0]=&(protdata->ntdb[3]);
527 else
528 protdata->sel_ntdb[0]=&(protdata->ntdb[1]);
529 protdata->sel_ctdb[0]=&(protdata->ctdb[1]);
531 /* set terminal residue numbers: */
532 snew(protdata->rN, NTERPAIRS);
533 snew(protdata->rC, NTERPAIRS);
534 protdata->rN[0]=0;
535 protdata->rC[0]=atoms->atom[atoms->nr-1].resnr;
537 /* keep unprotonated topology: */
538 protdata->upatoms = atoms;
539 /* we don't have these yet: */
540 protdata->patoms = NULL;
541 bUpdate_pdba=TRUE;
542 bKeep_old_pdba=TRUE;
544 /* clear hackblocks: */
545 protdata->nab=NULL;
546 protdata->ab=NULL;
548 /* set flag to show we're initialized: */
549 protdata->bInit=TRUE;
550 } else {
551 if (debug) fprintf(debug,"protonate: using available protdata\n");
552 /* add_h will need the unprotonated topoloy again: */
553 atoms = protdata->upatoms;
554 bUpdate_pdba=FALSE;
555 bKeep_old_pdba=FALSE;
558 /* now protonate */
559 nadd = add_h(&atoms, xptr, protdata->nah, protdata->ah,
560 NTERPAIRS, protdata->sel_ntdb, protdata->sel_ctdb,
561 protdata->rN, protdata->rC,
562 &protdata->nab, &protdata->ab, bUpdate_pdba, bKeep_old_pdba);
563 if ( ! protdata->patoms )
564 /* store protonated topology */
565 protdata->patoms = atoms;
566 *atomsptr = protdata->patoms;
567 if (debug) fprintf(debug,"natoms: %d -> %d (nadd=%d)\n",
568 protdata->upatoms->nr, protdata->patoms->nr, nadd);
569 return nadd;
570 #undef NTERPAIRS